在 Next.js 中使用 Redux 是一种反模式吗?

Jam*_*e S 69 redux react-redux next.js

我正在构建一个 Next.js 应用程序,它目前正在使用 Redux。在我构建它时,我想知道是否真的有必要使用 Redux,它的使用是否实际上是一种反模式。这是我的推理:

为了在 Next.js 中正确初始化 Redux Store,您必须App使用getInitialProps方法创建自定义组件。通过这样做,您将禁用Next.js 提供的自动静态优化

相比之下,如果我要在客户端包含 Redux,则只有在 App 挂载后,Redux 商店才会在每次服务器端导航后重置。例如,我有一个 Next.js 应用程序,它在客户端初始化 Redux 存储,但是当路由到动态路由(例如 )时pages/projects/[id],页面是服务器端呈现的,我必须重新获取店铺。

我的问题是:

  1. 在这种情况下,Redux 商店有什么好处?
  2. 我应该在根App组件中初始化商店并放弃自动静态优化吗?
  3. 有没有更好的方法来管理 Next.js 9.3 中的状态getStaticProps其他数据获取方法
  4. 我错过了什么吗?

ElD*_*n90 49

如果您有一个带有 getInitialProps 的自定义应用程序,那么 Next.js 提供的自动静态优化将对所有页面禁用。

没错,如果您遵循这种方法。

有没有更好的办法 ?

是的,您可以创建一个 Redux Provider 作为包装器并包装您需要的组件,redux 上下文将自动初始化并在该组件中提供。

例子:

const IndexPage = () => {
  // Implementation
  const dispatch = useDispatch()
  // ...
  // ...
  return <Something />;
}

IndexPage.getInitialProps = ({ reduxStore }) => {
  // Implementation
  const { dispatch } = reduxStore;
  // ...
  // ...
}

export default withRedux(IndexPage)
Run Code Online (Sandbox Code Playgroud)

您现在可以仅将 Redux 用于需要状态管理的页面,而无需禁用整个应用程序的优化。

回答你的问题“在 Next.js 中使用 Redux 是一种反模式吗?

不会,但需要正确使用。

有关如何在此处完成的更多信息:https : //github.com/vercel/next.js/tree/canary/examples/with-redux

我希望这有帮助

  • 在 Next.js 常见问题解答中,他们只是用状态提供程序包装 App,请参阅:https://github.com/vercel/next.js/blob/canary/examples/with-redux/src/pages/_app.tsx (5认同)

Yil*_*maz 14

我们使用 Redux 主要有两个原因。

1- 在组件之间传递数据。

如果你不使用 redux,那么你需要做 prop 钻孔。为了决定用户是否登录,我们获取数据,然后将其存储在 redux 存储中,然后 Header 组件连接到存储并获取身份验证信息。如果你没有使用redux,那么你需要在每个页面中获取用户,然后将其传递给Header组件。

Next.js 预渲染每个页面。这意味着 Next.js 会提前为每个页面生成 HTML,而不是全部由客户端 JavaScript 完成。预渲染可以带来更好的性能和 SEO。next-redux-wrapper包允许你使用带有自动静态优化的 redux。如果你点击链接,有一个注释说:“Next.js 在使用类 MyApp 时提供通用的 getInitialProps 扩展 App,它将被包装器拾取,所以你不能扩展 App,因为你会选择退出自动静态优化:”。我为我的项目设置了这个包,它很容易设置。

但是使用 redux 的缺点是它不是缓存。您存储数据,然后定期重新获取它以确保它是最新的。这是一项额外昂贵的工作。为了在 redux 中实现缓存,我们使用reselect库。这意味着你的项目在 redux 之上有额外的依赖,并且会让你编写更多的代码。

有一个很好的包swr它是由 next.js 创建的。Stale-While-Revalidate。它首先从缓存(陈旧)返回数据,然后发送获取请求,最后再次携带更新的数据。我在每个页面中选择使用这个。

import useSWR from "swr";

export const useGetUser = () => {
     // fetcher can be any asynchronous function which returns the data. useSwr will pass "/api/v1/me" to fetcher
     const { data, error, ...rest } = useSWR("/api/v1/me", fetcher);
     // !data && !error if both true, loading:true, data=null=>!data=true, error=null => !error=true
     return { data, error, loading: !data && !error, ...rest };
   };
Run Code Online (Sandbox Code Playgroud)

这是可重用的 fetcher

export const fetcher = (url: string) =>
  fetch(url).then(
    async (res: Response): Promise<any> => {
      const result = await res.json();

      if (res.status !== 200) {
        return Promise.reject(result);
      } else {
        return result;
      }
    }
  );
Run Code Online (Sandbox Code Playgroud)

2- 发出 api 请求。

我为我的项目设置了 redux 存储,它与我设置的文本编辑器冲突。Redux 以某种方式阻止了编辑器,我无法用我在编辑器上写的文本填充商店。所以我使用可重用的钩子来获取 api。一开始看起来很亲切,但如果你分析它,就会有道理。

export function useApiHandler(apiCall) {
  // fetching might have one those 3 states. you get error, you fetch the data, and you start with the loading state
  const [reqState, setReqState] = useState({
    error:null,
    data:null,
    loading:true, // initially we are loading 
  });
  const handler = async (...data) => {
    setReqState({ error: null, data: null, loading: true });
    try {
      // apiCall is a separate function to fetch the data
      const res = await apiCall(...data);
      setReqState({ error: null, data: res.data, loading: false });
      alert(res.data);// just to check it 
      return res.data;
    } catch (e) {
      // short circuting in or. if first expression is true, we dont evaluate the second.
      // short circuting in and. if first expression is true, result is the second expression
      const message =
        (e.response && e.response.data) || "Ooops, something went wrong...";
      setReqState({ error: message, data: null, loading: false });
      return Promise.reject(message);
    }
  };

  return [handler, { ...reqState }];
}
Run Code Online (Sandbox Code Playgroud)

一个简单的 apiCall 函数

  const createBlog = (data) => axios.post("/api/v1/blogs", data);
Run Code Online (Sandbox Code Playgroud)

然后这就是我们如何使用它:

  export const useCreateBlog = () => useApiHandler(createBlog);
Run Code Online (Sandbox Code Playgroud)

设置 redux 很容易,因为人们很容易不担心他们的应用程序的性能,他们只是设置它。在我看来,如果您有一个大型应用程序,您需要设置 redux,或者如果您熟悉 graphql,您可以使用 Apollo。这是一篇很好的文章,可以了解如何使用 apollo 作为状态管理。阿波罗作为国家管理。我建立了一个大型电子商务网站,并在我的新应用程序中使用了 redux,因为它相对较小,因此我不使用 next js,使其变得更复杂。