#SB7 + Next 13 + next/link

4 messages · Page 1 of 1 (latest)

split ether
#

Hi, I have install storybook 7 with npx storybook@next init and using @storybook/nextjs in my new Next JS 13 project and I can't seem to manage to make the next/link => <Link /> work inside a story (not to log in the actions panel but to actually navigate to the selected section in the main navigation). With Create React App + storybook 6 I was able to load a SPA in a story and use the navigation to browse between sections by adding a decorator, something like:

  return (
    <MemoryRouter>
      <Routes>
        <Route path="/*" element={<Story />} />
      </Routes>
    </MemoryRouter>
  );
};

export default {
  title: "Client/Website",
  component: App,
  decorators: [reactRouterDecorator],
} as ComponentMeta<typeof App>;```
 
Is there anyway to achieve the same with sb7 and Next 13? 

Many thanks
#

SB7 + Next 13 + next/link

austere moat
#

Hi @split ether,

first of all thank you for reaching out!

You can find a very detailed documentation of NextJS integration in Storybook 7 here: https://github.com/storybookjs/storybook/tree/next/code/frameworks/nextjs. Unfortunately, it is a bit hidden and not yet on our Storybook Website. We will figure out how to make framework-specific documentation more accessible and put it on the docs section of the Storybook website (cc @frozen pond).

It is important to know, whether your component should be used in the app or page directory of your Next.js project. If your component is in the page directory, you don't have to specify the router explicitly. If it is in the app directory though, please set the parameters.nextjs.appDirectory property to true (https://github.com/storybookjs/storybook/tree/next/code/frameworks/nextjs#nextjs-navigation)

Now lets try to understand, what happens if you interact with a Link. Let's assume, your component is in the page directory and you use next/router instead of next/navigation. In the background, the next/router tries to first prefetch the site on hover and then on click it will push the links href location to the router context. We have predefined logic, which will execute, if prefetch or push is triggered. The predefined logic looks approximately like this:

#
const defaultRouter = {
  push(...args) {
    action('nextRouter.push')(...args);
    return Promise.resolve(true);
  },
  replace(...args) {
    action('nextRouter.replace')(...args);
    return Promise.resolve(true);
  },
  reload(...args) {
    action('nextRouter.reload')(...args);
  },
  back(...args) {
    action('nextRouter.back')(...args);
  },
  forward() {
    action('nextRouter.forward')();
  },
  prefetch(...args) {
    action('nextRouter.prefetch')(...args);
    return Promise.resolve();
  },
  beforePopState(...args) {
    action('nextRouter.beforePopState')(...args);
  },
  events: {
    on(...args) {
      action('nextRouter.events.on')(...args);
    },
    off(...args) {
      action('nextRouter.events.off')(...args);
    },
    emit(...args) {
      action('nextRouter.events.emit')(...args);
    },
  },
  // The locale should be configured [globally](https://storybook.js.org/docs/react/essentials/toolbars-and-globals#globals)
  locale: globals?.locale,
  asPath: '/',
  basePath: '/',
  isFallback: false,
  isLocaleDomain: false,
  isReady: true,
  isPreview: false,
  route: '/',
  pathname: '/',
  query: {},
};

So we only trigger some actions, which are visible in the actions panel of Storybook.

You can now overwrite this behaviour, if you want:

// .storybook/preview.js

export const parameters = {
  nextjs: {
    router: {
      push(...args) {
        // The default implementation that logs the action into the Actions panel is lost
      },
    },
  },
};

Same accounts for next/navigation, if your component is in the app directory:

// .storybook/preview.js

export const parameters = {
  nextjs: {
    appDirectory: true,
    navigation: {
      push(...args) {
        // The default implementation that logs the action into the Actions panel is lost
      },
    },
  },
};

Please take a look at the provided documentation for more information and let me know, if you have further questions.