Nextjs 和上下文 API

IT技术 reactjs next.js react-context context-api
2021-05-15 12:03:01

使用 Next.js,我试图在 Context API 状态中获取数据后将它们保存在 中getInitialProps,以修复props钻孔。

但由于getInitialProps是静态方法,我们无法通过 this.context 访问它。我设法将它们保存在 componentDidMount 中,但在这种情况下,上下文状态在第一页加载时为空,直到填充为止。不确定在这种情况下最佳实践是什么。我应该在哪个生命周期中将初始数据保存到 Context 以便像 props 传递一样立即获得它们?

1个回答

您不能在 Next.js 服务器端 (SSR) 中使用 ContextAPI,因为它违反钩子规则。https://reactjs.org/warnings/invalid-hook-call-warning.html

React 将getInitialProps首先运行,因此最好的解决方案是在那里获取数据并使用 ContextAPI 将其传递给您的组件。

让我们继续看看它的工作方式如下:

创建您的 AppProvider 组件

实现您希望通过 React 组件传递的上下文提供程序功能。

对于这种情况,我们将创建将整个应用程序包装在其中的全局上下文提供程序。

const AppProvider = ({ children }) => {
  const [galleryData, setGalleryData] = React.useState([]);

  const handleGalleryData = galleryData => {
    setGalleryData(galleryData);
  }

  const contextProps = {
    galleryData,
    handleGalleryData
  };

  return (
    <AppContext.Provider value={contextProps}>
      {children}
    </AppContext.Provider>
  );
}

然后使用这个新的提供程序包装您的应用程序。

<AppProvider>
  <App />
</AppProvider>

并进入您的页面,例如index.js,请尝试以下方式:

Index.getInitialProps = async (props) => {
  const { req, res, query, ...others } = props;

  // use your env variables, endpoint URIs
  // ..

  ... fetch whatever you want..
  const galleryProps = await fetch(endpoint); // isomorphic-unfetch

  return {
    galleryProps,
    query,
    ...others
  };
}

根据您的 Next.js 版本,您可能会使用getServerSideProps代替getInitialProps,但请注意每个请求都会调用它。

Next.js 将使用 getServerSideProps Data Fetching docs返回的数据在每个请求上预渲染此页面

开始在您的组件上使用 ContextAPI

然后在您的组件中,您可以检查此数据并将其存储到 ContextAPI 中

const Index = props => {
  const { galleryProps, query, ...others } = props;
  const [galleryData, setGalleryData] = useState(galleryProps);
  const { handleGalleryData, ...contextRest } = useContext(AppContext);
  ...

  // Here you're going to store data into ContextAPI appropriatly.
  useEffect(() => {
    if (typeof galleryProps === 'object' && _.keys(galleryProps).length > 0) {
      handleGalleryData(galleryProps);
    }
  }, [handleGalleryData]);

  // Other times your page is loaded, you will GET this data from ContextAPI, instead of SSR props.
  useEffect(() => {
    if (_.keys(galleryDataProps).length <= 0 && _.keys(contextRest.galleryData).length > 0) {
      setGalleryData(contextRest.galleryData);
    }
  }, []);

....

return (
  <div>
    {JSON.stringify(galleryData)}
  </div>
);

上面的用例并不是最好的用例,但它让我们了解了 Next.js 应用程序中的 ContextAPI 是如何工作的。下面我来解释一下:

  • 第一个useEffect()是验证组件是否从通过 ContextAPI 存储它的 props 接收到数据对象。

  • 第二个检查商店是否有一些数据

您可以在getInitialProps加载组件之前以 SSR 模式获取数据

参考