Yas*_*sov 15 reactjs react-router react-router-dom rtk-query
最近react-router发布了新的 6.4,它能够在组件渲染之前加载数据。(https://reactrouter.com/en/main/start/overview#data-loading)
这看起来是一个很酷的功能。我想将它与 RTK 查询一起使用,因为我已经使用 Redux Toolkit。
所以我想做一件基本的事情,我有 api 来加载帖子。我想加载它们,如果请求失败 - 重定向到其他页面。在react-router6.4 中,这一切都可以在路由器中完成(https://reactrouter.com/en/main/start/overview#redirects)。
路由器超出了react的范围,所以我不能使用rtk查询提供的钩子,所以这意味着我必须使用没有钩子的rtk查询,根据文档这是完全可能的(https://redux-toolkit.router)。 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>
);
Run Code Online (Sandbox Code Playgroud)
我正在尝试使用文档中的示例,但我总是在控制台中获得“未初始化”状态,就像从未发出过请求一样,但确实如此,我可以在 redux dev 工具中看到数据。我还收到错误“在 找不到数据state.postsApi。您是否忘记将减速器添加到存储中?”
您在这里的方向是正确的,但是您需要对调度返回的 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()
}
},
Run Code Online (Sandbox Code Playgroud)
你可能会做一些类似的事情
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.
Run Code Online (Sandbox Code Playgroud)
请注意,我不会访问此处的数据,您可能也不应该访问。虽然在那之后它将可用await promise,但我只会使用加载器来呈现数据 - 然后使用useMyEndpointQuery(someArgument)组件中的法线来访问该数据。
您需要使用挂钩,以便缓存知道您的组件实际上正在使用该数据 - 否则它将在 60 秒后从缓存中删除(或者如果您从未取消订阅,则它永远不会被删除)。
此时,将数据从loader函数传递到组件中并没有真正的好处——无论如何,它已经能够通过钩子访问它了。
所以我的建议:启动并等待从 获取loader,但实际上像以前一样从组件访问数据。
| 归档时间: |
|
| 查看次数: |
4566 次 |
| 最近记录: |