设置 Storybook 以使用 Next.js 链接标签

Posted

技术标签:

【中文标题】设置 Storybook 以使用 Next.js 链接标签【英文标题】:Set up Storybook to work with Next.js's Link tag 【发布时间】:2020-04-29 22:07:05 【问题描述】:

我正在尝试为 Next.js 项目设置 Storybook。我有一个从 Next.js 呈现 Link 标记的组件。我的问题是,当我加载这个组件时,Storybook 会抛出以下错误:

Cannot read property 'pageLoader' of null
   at Link.handleRef

要让 Storybook 使用 Next.js 路由,特别是渲染 Link 标记,需要做什么?

更新:导致错误的代码:

// button-component.js
import Link from 'next/link.js';
import t from 'prop-types';
import React from 'react';

function Button( as, children, href, ...props ) 
  const isExternal = href && href.startsWith('http');
  const a = (
    <a href=href ...props>
      children
    </a>
  );

  if (href) 
    return isExternal ? (
      a
    ) : (
      <Link href=href as=as>
        a
      </Link>
    );
  

  return (
    <button type="button" ...props>
      children
    </button>
  );


Button.propTypes = 
  as: t.string,
  children: t.node,
  href: t.string,
;

export default React.memo(Button);
// button.stories.js
import React from 'react';

import Button from './button-component';

export default 
  title: 'Button',
;

export const standardButton = () => <Button>Standard Button</Button>;

export const internalLink = () => <Button href='/buy'>
  Internal Link
</Button>;

export const externalLink = () => (
  <Button target="_blank" href="https://www.hopin.to">
    External Link
  </Button>
);

【问题讨论】:

你能贴一些代码吗? 下一个版本是什么? @Cully 当然,完成! @felixmosh Next.js:“9.1.7”,故事书:“5.3.1” 你能设置一个小仓库来重现这个问题吗? 【参考方案1】:

我在 Next.js 的 github 上发现了一个关于此问题的报告:https://github.com/zeit/next.js/issues/9951

仅在 5 天前报告了此问题,因此您可能遇到了同样的问题。解决方法是升级到nextjsv9.1.8-canary.6。阅读更多有关此内容并查看源代码,这可能是您的问题。此外,如果您想尝试更新的东西,nextjs 还有更新的金丝雀版本。

如果这不能解决它,我的另一个猜测是您遇到错误,因为您在 Next.js 页面之外使用Link。 Next.js 可能在幕后包含页面的依赖项。 Link 可能依赖于这些依赖项,并在找不到它们时抛出错误。如果你想在 Next.js 页面之外测试你的组件,你可以创建一个自定义的 Link 组件来测试你是否在 Next.js 中,如果你在,则只呈现 Link。例如:

import Link from 'next/link'
import Router from 'next/router'

const CustomLink = (children, ...otherProps) => 
  const isPage = () => 
    // if we're in a next.js route, then Router.router will be set
    return Boolean(Router.router)
  

  return isPage()
    ? (<Link ...otherProps>children</Link>)
    : children

然后使用CustomLink 而不是Link

【讨论】:

您可以使用process.env.STORYBOOK === 'true' 来代替isPage() 函数。这种方法不会隐藏错误,以防您的代码在故事书之外运行并且由于某种原因没有路由器上下文

以上是关于设置 Storybook 以使用 Next.js 链接标签的主要内容,如果未能解决你的问题,请参考以下文章

Storybook 在 React、Next.JS、Typescript 项目中找不到组件

如何使用 Next.js、Ant Design、Less 和 TypeScript 配置 Storybook.js Webpack

通过 next.js 路由覆盖故事书路由

使用 Nextjs 在 Netlify 上部署 Storybook

如何在 Storybook 中使用 NextJS 的 'useRouter()' 钩子

如何在 next.js 中管理 i18n 路由以使用斜杠而不是破折号