I am using react-router-dom@6.8.1
along with redux-toolkit
. I have a typical scenario where I'm making a backend call to fetch data (this is happening inside a loader function offered by RRD).
Once I fetch the data, I need to update the redux state inside the loader function. (This way, I can avoid another useEffect
inside my function component). Here is a code snippet to give you a better understanding.
const router = createBrowserRouter([
{
path: "/",
errorElement: <Error />,
children: [
{
index: true,
element: <Home />,
loader: async () => {
try {
const response = await axios({
method: "get",
url: "some URL here",
});
// State update should happen here using dispatch. **********
return response;
} catch (e: any) {
throw json(
{ message: "Error occured while fetching data" },
{ status: e.status }
);
}
},
},
],
},
]);
Since we cannot use useDispatch
outside of the React function components or custom hooks, I am wondering if there is any way to achieve this.
I am glad to provide any more details like package.json etc, upon requirement.
You can do that by wrapping the rendering of your routes inside a component. For example, something like so in index.js
:
function Index() {
const dispatch = useDispatch();
const router = createBrowserRouter([
{
path: "/",
errorElement: <Error />,
children: [
{
index: true,
element: <Home />,
loader: async () => {
try {
const response = await axios({
method: "get",
url: "some URL here",
});
dispatch({ type: "Something" });
return response;
} catch (e: any) {
throw json({ message: "Error occured while fetching data" }, { status: e.status });
}
},
},
],
},
]);
return <RouterProvider router={router} />;
}
// As of React 18
const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(
<Provider store={store}>
<Index />
</Provider>
);
If you want to pass dispatch
as a parameter to a loader in a different file, you could use a function that returns the loader that React Router Dom expects, like so, for example:
const loadereGetter = (dispatch) => async () => {
try {
const response = await axios({
method: "get",
url: "some URL here",
});
dispatch({ type: "Something" });
return response;
} catch (e: any) {
throw json({ message: "Error occured while fetching data" }, { status: e.status });
}
};
function Index() {
const dispatch = useDispatch();
const router = createBrowserRouter([
{
path: "/",
errorElement: <Error />,
children: [
{
index: true,
element: <Home />,
loader: loaderGetter(dispatch),
},
],
},
]);
return <RouterProvider router={router} />;
}
// As of React 18
const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(
<Provider store={store}>
<Index />
</Provider>
);