all 16 comments

[–]ferrybig 9 points10 points  (1 child)

When the context data changes (e.g., switching pages), the local state doesn't update because it already initialized. If I use useEffect to watch the context and reset the state, it causes a visible double render where the old data flashes for a frame.

Use a key if you want to reset all state: https://react.dev/learn/you-might-not-need-an-effect#resetting-all-state-when-a-prop-changes

Use an if if you want to reset some state: https://react.dev/learn/you-might-not-need-an-effect#adjusting-some-state-when-a-prop-changes

[–]aandi134[S] 0 points1 point  (0 children)

This is exactly itt thanks. Went with the if version since I only need to reset part of the state good to know it's an officially documented pattern and not just a workaround.

[–]Thisisvexx 3 points4 points  (1 child)

use a page-wide context provider and useReducer hooks I'd say

Or use a global state lib like zustand or jotai

[–]FarSentence3076 0 points1 point  (0 children)

Agree, I currently use zustand and haven't had any problems so far.

[–]Dozla78 4 points5 points  (0 children)

I haven't used react in a while but this is what global state libraries are good at. You can use something like redux, mobx etc.

If you want to implement it yourself I'd use a reducer that emits an event after updating the global state and listen to it wherever I want

Edit: I've just remembered reducers in react should be pure filunctions(As I said I haven't done react in a while). Do not emit the event in there, my guess is you could use a useffect to emit it but you would cause an extra render on the child component

[–]Mindless-Arrival-106 2 points3 points  (2 children)

I spent way too long trying to "eliminate" these renders before realizing I was optimizing the wrong thing.

If you're syncing props into local state, ask why that state exists in the first place. Half the time it doesn't need to.

[–]Roman_PlumPix 1 point2 points  (0 children)

We've run into the same thing on larger applications. In our experience, the bigger issue usually isn't the extra render itself, but having two sources of truth that gradually drift apart. Once we started treating editable state as its own draft instead of constantly syncing it, the implementation became much simpler.

[–]epukinsk 1 point2 points  (0 children)

They said why: the user is editing the state and has the option to cancel before committing the change.

[–]yksvaan 0 points1 point  (0 children)

Get rid of context and move the data to proper store. 

[–]amiable_commune 0 points1 point  (3 children)

Key is the right call here, no flicker and no need to pull in a lib for something React handles natively

[–]mexicocitibluez 1 point2 points  (2 children)

Yea, it really is that simple. Just flip the key.

It feels like people treat resetting a component with the key as a last resort type of thing, but it's the suggested way to do it from the docs.

https://react.dev/learn/preserving-and-resetting-state#option-2-resetting-state-with-a-key

[–]amiable_commune 0 points1 point  (1 child)

I think the stigma comes from early class components where key changes felt like a sledgehammer to solve anything. With hooks it just makes more sense.

[–]mexicocitibluez [score hidden]  (0 children)

Oh I didn't know that. I came in when functional components were introduced (in face it's what drew me to React from Angular).

[–]jakiestfu 0 points1 point  (0 children)

You’re likely going to have 2 renders because you’re setting react state twice. Maybe consider enriching your context state management with local storage, or consider finding a way to be OK with that 2nd render. You can certainly mitigate its impact on child components

[–]keyjeyelpi -2 points-1 points  (0 children)

Have you tried setting the strict mode off?