Skip to content

Commit

Permalink
tMerge pull request #23296 from storybookjs/valentin/fix-next-images-…
Browse files Browse the repository at this point in the history
…in-latest-release

Next.js: Fix next/image usage in latest Next.js release

(cherry picked from commit d4a3a23)
  • Loading branch information
valentinpalkovic authored and shilman committed Jul 4, 2023
1 parent 19f91cd commit 40f4981
Show file tree
Hide file tree
Showing 4 changed files with 196 additions and 129 deletions.
43 changes: 39 additions & 4 deletions code/frameworks/nextjs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
- [Set `nextjs.appDirectory` to `true`](#set-nextjsappdirectory-to-true)
- [Overriding defaults](#overriding-defaults-1)
- [Global Defaults](#global-defaults-1)
- [`useSelectedLayoutSegment` and `useSelectedLayoutSegments` hook](#useselectedlayoutsegment-and-useselectedlayoutsegments-hook)
- [`useSelectedLayoutSegment` `useSelectedLayoutSegments` and `useParams` hook](#useselectedlayoutsegment-useselectedlayoutsegments-and-useparams-hook)
- [Default Navigation Context](#default-navigation-context)
- [Actions Integration Caveats](#actions-integration-caveats-1)
- [Next.js Head](#nextjs-head)
Expand Down Expand Up @@ -499,9 +499,9 @@ export const parameters = {
};
```

#### `useSelectedLayoutSegment` and `useSelectedLayoutSegments` hook
#### `useSelectedLayoutSegment` `useSelectedLayoutSegments` and `useParams` hook

The `useSelectedLayoutSegment` and `useSelectedLayoutSegments` hooks are supported in Storybook. You have to set the `nextjs.navigation.segments` parameter to return the segments you want to use.
The `useSelectedLayoutSegment` `useSelectedLayoutSegments` and `useParams` hooks are supported in Storybook. You have to set the `nextjs.navigation.segments` parameter to return the segments or the params you want to use.

```js
// SomeComponentThatUsesTheNavigation.stories.js
Expand All @@ -522,11 +522,46 @@ export default {
export const Example = {};

// SomeComponentThatUsesTheNavigation.js
import { useSelectedLayoutSegment, useSelectedLayoutSegments } from 'next/navigation';
import { useSelectedLayoutSegment, useSelectedLayoutSegments, useParams } from 'next/navigation';

export default function SomeComponentThatUsesTheNavigation() {
const segment = useSelectedLayoutSegment(); // dashboard
const segments = useSelectedLayoutSegments(); // ["dashboard", "analytics"]
const params = useParams(); // {}
...
}
```

To use `useParams`, you have to use a two string elements array for a segment, the first array element is the param key and the second array element is the param value.

```js
// SomeComponentThatUsesParams.stories.js
import SomeComponentThatUsesParams from './SomeComponentThatUsesParams';

export default {
component: SomeComponentThatUsesParams,
parameters: {
nextjs: {
appDirectory: true,
navigation: {
segments: [
['slug', 'hello'],
['framework', 'nextjs'],
]
},
},
},
};

export const Example = {};

// SomeComponentThatUsesParams.js
import { useSelectedLayoutSegment, useSelectedLayoutSegments, useParams } from 'next/navigation';

export default function SomeComponentThatUsesParams() {
const segment = useSelectedLayoutSegment(); // hello
const segments = useSelectedLayoutSegments(); // ["hello", "nextjs"]
const params = useParams(); // { slug: "hello", framework: "nextjs" }
...
}
```
Expand Down
86 changes: 55 additions & 31 deletions code/frameworks/nextjs/src/routing/app-router-provider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import React from 'react';
import type {
LayoutRouterContext as TLayoutRouterContext,
AppRouterContext as TAppRouterContext,
GlobalLayoutRouterContext as TGlobalLayoutRouterContext,
} from 'next/dist/shared/lib/app-router-context';
import type {
PathnameContext as TPathnameContext,
Expand All @@ -21,17 +22,21 @@ let AppRouterContext: typeof TAppRouterContext;
let LayoutRouterContext: typeof TLayoutRouterContext;
let PathnameContext: typeof TPathnameContext;
let SearchParamsContext: typeof TSearchParamsContext;
let GlobalLayoutRouterContext: typeof TGlobalLayoutRouterContext;

try {
AppRouterContext = require('next/dist/shared/lib/app-router-context').AppRouterContext;
LayoutRouterContext = require('next/dist/shared/lib/app-router-context').LayoutRouterContext;
PathnameContext = require('next/dist/shared/lib/hooks-client-context').PathnameContext;
SearchParamsContext = require('next/dist/shared/lib/hooks-client-context').SearchParamsContext;
GlobalLayoutRouterContext =
require('next/dist/shared/lib/app-router-context').GlobalLayoutRouterContext;
} catch {
AppRouterContext = React.Fragment as any;
LayoutRouterContext = React.Fragment as any;
PathnameContext = React.Fragment as any;
SearchParamsContext = React.Fragment as any;
GlobalLayoutRouterContext = React.Fragment as any;
}

type AppRouterProviderProps = {
Expand All @@ -52,43 +57,62 @@ const getParallelRoutes = (segmentsList: Array<string>): FlightRouterState => {
const AppRouterProvider: React.FC<AppRouterProviderProps> = ({ children, action, routeParams }) => {
const { pathname, query, segments = [], ...restRouteParams } = routeParams;

const tree: FlightRouterState = [pathname, { children: getParallelRoutes([...segments]) }];

// https://github.com/vercel/next.js/blob/canary/packages/next/src/client/components/app-router.tsx#L436
return (
<AppRouterContext.Provider
value={{
push(...args) {
action('nextNavigation.push')(...args);
},
replace(...args) {
action('nextNavigation.replace')(...args);
},
forward(...args) {
action('nextNavigation.forward')(...args);
},
back(...args) {
action('nextNavigation.back')(...args);
},
prefetch(...args) {
action('nextNavigation.prefetch')(...args);
},
refresh: () => {
action('nextNavigation.refresh')();
},
...restRouteParams,
}}
>
<PathnameContext.Provider value={pathname}>
<SearchParamsContext.Provider value={new URLSearchParams(query)}>
<LayoutRouterContext.Provider
<GlobalLayoutRouterContext.Provider
value={{
childNodes: new Map(),
tree: [pathname, { children: getParallelRoutes([...segments]) }],
url: pathname,
headRenderedAboveThisLevel: true,
changeByServerResponse() {
// NOOP
},
tree,
focusAndScrollRef: {
apply: false,
hashFragment: null,
segmentPaths: [tree],
},
nextUrl: pathname,
}}
>
<PathnameContext.Provider value={pathname}>{children}</PathnameContext.Provider>
</LayoutRouterContext.Provider>
<AppRouterContext.Provider
value={{
push(...args) {
action('nextNavigation.push')(...args);
},
replace(...args) {
action('nextNavigation.replace')(...args);
},
forward(...args) {
action('nextNavigation.forward')(...args);
},
back(...args) {
action('nextNavigation.back')(...args);
},
prefetch(...args) {
action('nextNavigation.prefetch')(...args);
},
refresh: () => {
action('nextNavigation.refresh')();
},
...restRouteParams,
}}
>
<LayoutRouterContext.Provider
value={{
childNodes: new Map(),
tree,
url: pathname,
}}
>
{children}
</LayoutRouterContext.Provider>
</AppRouterContext.Provider>
</GlobalLayoutRouterContext.Provider>
</SearchParamsContext.Provider>
</AppRouterContext.Provider>
</PathnameContext.Provider>
);
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import {
useRouter,
usePathname,
useSearchParams,
useParams,
useSelectedLayoutSegment,
useSelectedLayoutSegments,
} from 'next/navigation';
Expand All @@ -11,6 +12,7 @@ function Component() {
const router = useRouter();
const pathname = usePathname();
const searchParams = useSearchParams();
const params = useParams();
const segment = useSelectedLayoutSegment();
const segments = useSelectedLayoutSegments();

Expand Down Expand Up @@ -58,6 +60,16 @@ function Component() {
))}
</ul>
</div>
<div>
params:{' '}
<ul>
{Object.entries(params).map(([key, value]) => (
<li key={key}>
{key}: {value}
</li>
))}
</ul>
</div>
{routerActions.map(({ cb, name }) => (
<div key={name} style={{ marginBottom: '1em' }}>
<button type="button" onClick={cb}>
Expand Down Expand Up @@ -96,3 +108,17 @@ export const WithSegmentDefined = {
},
},
};

export const WithSegmentDefinedForParams = {
parameters: {
nextjs: {
appDirectory: true,
navigation: {
segments: [
['slug', 'hello'],
['framework', 'nextjs'],
],
},
},
},
};

0 comments on commit 40f4981

Please sign in to comment.