Nextjs和上下文API

时间:2019-01-10 11:23:44

标签: reactjs next.js

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

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

1 个答案:

答案 0 :(得分:0)

Next.js首先在客户端中进行SSR加载,因此最好的解决方案是使用getInitialProps方法获取数据,而不是通过组件传递数据。

  

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

让我们继续前进,看看它是否在波纹管中工作:

在您的_app.js文件中,创建您的提供程序函数:

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;

  console.log('-- index SSR props: ', query, others);

  const { serverRuntimeConfig } = getConfig();

  console.log('SSR config: ', serverRuntimeConfig);
  const { unsplash } = serverRuntimeConfig;


  ... fetch whatever you want..
  const gallery = await getGallery(unsplash); // external method.

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

比在组件中,您可以检查此数据并将其存储到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>
);

请记住,getInitialProps仅在加载组件时加载一次。因此,您无法在页面下次加载时从SSR道具获取数据,这就是为什么我们需要使用诸如ContextApiRedux之类的商店管理的原因,否则您每次都会获取相同的数据转到上一页。