reactjs 如何在React路由器6.4中读取RTK查询状态

xxslljrj  于 2022-12-26  发布在  React
关注(0)|答案(2)|浏览(128)

最近发布了新的react-router 6.4,它能够在渲染组件之前加载数据。(https://reactrouter.com/en/main/start/overview#data-loading)
这看起来是一个很酷的功能。而且我想把它和RTK查询一起使用,因为我已经在使用Redux工具包了。
所以我想做一个基本的事情,我有加载帖子的API。我想加载它们,如果请求失败-重定向到其他页面。在react-router 6.4中,这一切都可以在路由器中完成(https://reactrouter.com/en/main/start/overview#redirects)。
Router不在react的范围内,因此我无法使用rtk query提供的钩子,这意味着我必须使用没有钩子的rtk query,根据文档,这是完全可能的(https://redux-toolkit.js.org/rtk-query/usage/usage-without-react-hooks
所以我的问题是,如何在react-router加载器中读取请求的状态。我可以使用钩子读取组件中的状态,但这会使组件“脏”,并将逻辑分散到整个应用程序中。

import React from "react";
import ReactDOM from "react-dom/client";

import { createBrowserRouter, RouterProvider } from "react-router-dom";

import { Provider } from "react-redux";
import { store } from "./redux/redux";

import { Comments } from "./Comments";
import { Posts } from "./Posts";
import { Root } from "./Root";

import { postsApi } from "./redux/redux";

const router = createBrowserRouter([
  {
    path: "/",
    element: <Root />,
  },
  {
    path: "posts",
    element: <Posts />,
    loader: () => {
      store.dispatch(postsApi.endpoints.getPosts.initiate());

      const request = postsApi.endpoints.getPosts.select()(store);

      console.log(request);

      return request;
    },
  },
  {
    path: "/comments",
    element: <Comments />,
  },
]);

const root = ReactDOM.createRoot(
  document.getElementById("root") as HTMLElement
);
root.render(
  <Provider store={store}>
    <RouterProvider router={router} />
  </Provider>
);

我尝试使用文档中的示例,但我总是在控制台中得到“未初始化”状态,就像从未发出过请求一样,但它确实是,我可以在redux开发工具中看到数据。而且我还得到错误“在state.postsApi处未找到数据。您忘记将reducer添加到存储区吗?”

hi3rlvi2

hi3rlvi21#

你可能会做一些沿着的事情

const promise = dispatch(api.endpoints.myEndpoint.initiate(someArgument))
await promise // wait for data to be there
promise.unsubscribe() // remove the subscription. The data will stay in cache for 60 seconds and the component can subscribe to it in that timeframe.

请注意,我不会在这里访问数据,您可能也不应该访问,虽然在await promise之后它将可用,但我将仅在数据出现时使用加载器-然后使用组件中的常规useMyEndpointQuery(someArgument)访问该数据。
您需要使用钩子,该高速缓存知道您的组件实际上正在使用该数据-否则它将在60秒后从缓存中删除(或者如果您从未取消订阅,它将永远不会被删除)。
此时,将数据从loader函数传递到组件中并没有什么真实的好处-无论如何,组件已经能够通过钩子访问数据了。
所以我的建议是:启动并等待从loader获取数据,但实际上像以前一样从组件访问数据。

3zwjbxry

3zwjbxry2#

您的思路是正确的,但是您需要对dispatch返回的promise调用unwrap(),如果成功则返回结果,如果不成功则抛出。

loader: () => {
      const p = store.dispatch(postsApi.endpoints.getPosts.initiate());

      try {
        const response = await p.unwrap()
        return response
      } catch (e) {
        // see https://reactrouter.com/en/main/fetch/redirect
        return redirect("/login")
      } finally {
        p.unsubscribe()
      }
    },

相关问题