The main issue is that the render prop in <Route /> component was forcing the content of this route to re-render every time the location has changed but with v6 we struggled to find a way to do the same.
Is there an official way of doing the same what a render prop in <Route /> component was used to do in the old v5 implementation?
<HashRouter>
<Route render={() => <Bar />} />
<Switch>
<Route path="/foo" exact={false} component={Foo} />
<Route path="/foo/:id" exact={true} component={Foo} />
<Route path="/foo/:id/:lang" component={Foo} />
<Redirect to="/foo" />
</Switch>
</HashRouter>
No matter where you navigate, the <Bar /> component will always re-render.
<HashRouter>
<Routes>
<Route path="*" element={<Bar />}>
<Route path="return" element={<Navigate to="/foo" />} />
<Route path="foo">
<Route path="/" element={<Foo />} />
<Route path=":id" element={<Foo />} />
<Route path=":id/:lang" element={<Foo />} />
</Route>
</Route>
</Routes>
</HashRouter>
and the<Bar /> component looks like this:
const Bar = () => {
const {key} = useLocation();
console.log('==> bar');
return <Outlet key={key} />;
};
Now this does the same as the v5 example above.
Is this a valid solution? Is there a better way of doing the same?
Thank you
You should be using hooks, rather than trying to get Route to re-render your component. This is better because it will always re-render when the location changes, not just when placed under a Route component.
@timdorr While I didn't post this, I disagree that the hooks are necessarily always better.
If I were to use hooks I would need to either 1. fundamentally couple pages to the routes or 2. create new wrapper components to maintain decoupling. Option 1 is highly undesirable at my work since we use the same pages in multiple apps (i.e. user pages duplicated within the admin app) as a different route. Option 2 seems incredibly verbose and really begs the question whether or not this approach really increases DX or readability. I may be missing something, but the render approach really worked quite well even in the brand new hooks world.
You should be using hooks, rather than trying to get Route to re-render your component. This is better because it will always re-render when the location changes, not just when placed under a Route component.
Can you give us an example how to do it with hooks? I mean to have the exact functionality as the render prop.
As far as I know the hook will only be fired once the path of the functional component matches the location, while the render prop was doing that also if the route was not matching because it knew that there was a location change.
Thanks.
@Bekaxp Solution:
const Bar = () => {
const {pathname} = useLocation();
console.log('==> side-effect for', pathname);
return null;
};
...
<HashRouter>
<Routes>
<Route path="return" element={<Navigate to="/foo" />} />
<Route path="foo">
<Route path="/" element={<Foo />} />
<Route path=":id" element={<Foo />} />
<Route path=":id/:lang" element={<Foo />} />
</Route>
</Routes>
<Bar />
</HashRouter>
Note: see <Bar /> is located outside of the <Routes> and triggers the side-effect in any location change.
@artola Thanks, thats way cleaner.
Most helpful comment
@Bekaxp Solution:
Note: see
<Bar />is located outside of the<Routes>and triggers the side-effect in any location change.