Parent component:
<Main props... >
<LinksArray />
<Outlet context={investorId}/>
</Main>
outlet component
const NewBoards: React.FC = () => {
let { boardId } = useParams();
// this does not
useEffect(() => {
console.log('ue trigger page change',boardId )
}, []);
// this triggers (because of an argument
useEffect(() => {
console.log('ue trigger page change',boardId )
}, [boardId ]);
return (
<>
{console.log('>rerender')}
<p> newBoards</p>
<p>{boardId}</p>
</>
)
}
NewBoards is an outlet element, I would love for useEffect to trigger on a ROUTE (ex. boards/123 to boards/345 ) change, without passing boardId, however useEffect does not trigger on the address change unless I`m passing boardId to the dependency array. boardId param does change.
Also I would like to know why that useEffect does not trigger. I can't find anything related to it on the react router v6 official documentation
edit:
I have also noticed that states are saved. States inside outlet component( NewBoards ) do not refresh to initial ones.
edit ( router definition ) :
{
path: '/boards/',
element: authorized ? <Boards1 /> : <Login />,
children: [{
path: '/boards/:boardId',
element: authorized ? <NewBoards /> : <Login />,
}]
},
From what I see from your comments you've seriously misunderstood what is happening between the Outlet
and the nested Route
components that are rendering their content, i.e. element
prop, into it.
Assuming authorized
is true then the following route config:
{
path: '/boards/',
element: authorized ? <Boards1 /> : <Login />,
children: [{
path: '/boards/:boardId',
element: authorized ? <NewBoards /> : <Login />,
}]
},
will produce the following rendered routes:
<Routes>
...
<Route path="/boards" element={<Boards1 />}>
<Route path="/boards/:boardId" element={<NewBoards />} />
</Route>
...
</Routes>
Where I think your understanding goes awry is in thinking that when the URL path changes from "/boards/123"
to "/boards/345"
that the Boards1
component rendered on "/boards"
will rerender and remount the Outlet
. It won't. This means that the Outlet
it is rendering also doesn't do anything other than output the result of the currently matched route.
A second point of confusion/misudnerstanding on your part is thinking that when the URL path changes from "/boards/123"
to "/boards/345"
that <Route path="/boards/:boardId" element={<NewBoards />} />
will unmount and remount a new instance of the NewBoards
component. This is also not the case. The NewBoards
component will remain mounted and will simply rerender. This is an optimization by react-router-dom
as it's a lot more work to tear down and remount a component than it is to simply rerender it with some different props/context/etc.
The routed components using the route path params necessarily need to "listen" to changes to the params if they need to issue side-effects
based on the param values. This is why the useEffect
hook with empty dependency array runs only once when the NewBoards
component was mounted (not each time the route changes) and the useEffect
hook with the boardId
param as a dependency correctly reruns each time the boardId
value changes.
const NewBoards: React.FC = () => {
const { boardId } = useParams();
// Run this when component mounts, occurs once per mounting
useEffect(() => {
console.log('ue trigger page change', boardId);
}, []);
// Run this when the `boardId` param updates
useEffect(() => {
console.log('ue trigger page change', boardId);
}, [boardId]);
// Run this each render, i.e. no dependency array at all!
useEffect(() => {
console.log('>rerender');
});
return (
<>
<p>newBoards</p>
<p>{boardId}</p>
</>
);
};