When you need re-render, but it doesn't happen...
I already have had this issue and was surprised by this behaviour, but I forgot this ā and wasted 2 hours on debugging. I suspected componentās library, checked contexts, and tried to find problems in composition.
So, what happened? In our App.tsx
:
<Router history={history}> <UuiContext.Provider value={services}> <Header /> <Routes /> <Footer /> </UuiContext.Provider></Router>
In Header.tsx
ā navigation:
// it's component from library, responsible for highlighting active menu item// use uuiContext from UuiContext.Provider and check is link active using history<MainMenu> <MainMenuButton caption='Home' link={{pathname: '/' } /> <MainMenuButton caption='Dashboard' link={{pathname: '/dashboard' } /></MainMenu>
And it worksā¦ almost. When you click on buttons in MainMenu url is updated, content is re-rendered. But there is no highlighting for active menu item in MainMenu.
Started with MainMenu.tsx
: add breakpoint in function defining is link active.
But on button clicks and changing url this function is not called. And component is not re-rendered.
Add console.log(ārenderā) in Header.tsx
. So, it is also not re-rendered.
Despite updating the history object, and seeing those updates reflected in uuiContext.uuiRouter.history,
nothing was triggering a re-render.
Why donāt children of UuiContext.Provider update?
At this point, I went down a rabbit hole: tried to debug in contexts, because I thought that I have several instances and something weird happens. Found nothing, of course.
But after all this debugging, idea occurred to me: content is re-rendered because of changing
actual Route, what if I put Header
in corresponded pages?
It worked, but in this case Header
unmounted and mounted each time route changes. Itās not good
user experience.
And then finally I asked right thing: how React and React Router define, what should be re-rendered? Results of answering on this question:
- we update history
- history object is stable reference, so you cannot track changes with useEffect and history.location dependency
- but useLocation and useParams watch changes location, and when we use them ā our component re-renders after changes
So I just added to Header.tsx
:
useLocation();
//...same code
The most annoying thing about that I already have solved problem like this, but remembered about it only when I found solution again. Writing it down this time so Iāll remember š¤Ŗ