I have read that createBrowserRouter
should be outside React function, I could not find anyway/tutorial that show how to pass props to the components, should I use (useContext
) in this case? Are there any other options?
const router = createBrowserRouter(
createRoutesFromElements(
<Route path="/" element={<Layout />}>
<Route index element={<Home articles={articles} />} />
<Route path="About" element={<About />} />
</Route>
)
);
export function App() {
const [articles, setArticles] = useState();
return (
<div>
<RouterProvider router={router} />
</div>
);
}
Yes, you should typically declare the router once outside the React tree, but as you see with your example this simply doesn't work.
A trivial solution is to create and memoize the router within the React tree.
Example:
export function App() {
const [articles, setArticles] = useState();
const router = React.useMemo(() => createBrowserRouter(
createRoutesFromElements(
<Route path="/" element={<Layout />}>
<Route index element={<Home articles={articles} />} />
<Route path="About" element={<About />} />
</Route>
)
), [articles]);
return (
<div>
<RouterProvider router={router} />
</div>
);
}
Moving any state and updaters/callbacks into a React context would be an optimization, and would also allow for keeping the router declaration outside the React tree. Here I would recommend integrating the React context as a layout route component and provide the context value on React-Router's Outlet
provided context.
Example:
const ArticlesLayout = () => {
const [articles, setArticles] = useState();
return <Outlet context={{ articles, /* any additional values */ }} />;
};
Wrap only the routes that need to access the articles
state and any callbacks.
const router = createBrowserRouter(
createRoutesFromElements(
<Route path="/" element={<Layout />}>
<Route element={<ArticlesLayout />}>
<Route index element={<Home />} />
</Route>
<Route path="About" element={<About />} />
</Route>
)
);
export function App() {
return (
<div>
<RouterProvider router={router} />
</div>
);
}
The Home
component would now access the articles
state via the useOutletContext
hook.
import { useOutletContext } from 'react-router';
export const Home = () => {
const { articles } = useOutletContext();
...
};