Closed utterances-bot closed 2 years ago
Great article, made things click for me. Great to see some of the things Brian talked about from a hooks perspective. Hope they put something like this in the upcoming new React docs!
If my understand is correct, the "Please mount this whenever the key changes. As long as the key is the same, please re-render" should be "Please mount this whenever the key changes. As long as the key is NOT the same, please re-render"
@YagamiNewLight no, that is not correct. If the key changes, the component will be un-mounted and re-mounted, thus state will be newly initialized. As long as the key stays the same, the component will "just re-render" (no unmounting happens), which means that initial state passed to useState will be ignored. Hope that clears it up :)
Many thanks, I got the point. I very like your blogs, I can learn much from it. :p
Hi. Thanks for the article. Here you write "As long as the key is the same, please re-render". But what causes a re-render though no state changes.
@gezichenshan the state change happens in the App
component when the selected
state changes. From there on, all children will be re-rendered. But we can "force" react to re-mount a child instead of "just" re-rendering it by providing a different key
prop.
@TkDodo yeah, I got it. I mixed the concept of re-render and re-mount. Thanks!
@TkDodo how would u force react to re-mount a child component?
@OkoloJohnbosco like I said above - by providing a different key
prop. Kent also has a good article on this topic: https://kentcdodds.com/blog/understanding-reacts-key-prop
Thank you
I'm not sure I completely agree:
With regards to the example that if the data changes in a parent component and the user already changed the value in the input field and you wouldn't want to override the user input - That would happen (overriding user input) in the stable key solution as well.
What happens when you: a. can't use a modal UI b. don't want to re-render the app as you said (so lifting state up is not a viable option) c. Don't want to unmount and mount DetailView with the key solution because DetailView is a larger component that is costly to mount for some reason. Would you support the useEffect syncing then?
Thanks for the article!
@bartzy
That would happen (overriding user input) in the stable key solution as well.
It would, but only at distinct points where you want it. For example, imagine a user list with a detail form that displays a couple of user-related fields next to it. Selecting the user in the list will populate the detail view. When you change to a different user in the list view, you explicitly want to override all input fields. That's why using the user.id
as key
for the detail form seems like a good choice.
Would you support the useEffect syncing then?
There are always exceptions. For example, I've recently used a useEffect
to sync state from the url
to a FilterForm: When the user hits apply in the filter form, it is lifted up to the url, so that queries can consume it (subscribed via useLocation
from react-router). If the user navigates back in the browser history, the url changes, so we explicitly want to set our FilterForm to that state. Since there is no good key to use (except json.stringify the whole params), the effect worked better.
It's just that I've seen syncing state, e.g. from redux to local state a lot as the default approach, and I think that's not a good idea :)
Assuming that persons
is a server-state cached on the client via react-query and we could select and mutate on the same screen the data how would you handle selected
.
Here a sandbox for your reference (https://codesandbox.io/s/stupefied-dream-vmy76?file=/src/SelectView.js).
selected
is set to undefined
and is not re-rendered once the data is fetched.selected
are not. On top of my mind I would use useEffect
, but I would lose all the UI changes once the data is refetched. How would you address this type of issue?
There are basically two ways to solve this, both of which I have outlined here:
https://tkdodo.eu/blog/practical-react-query#keep-server-and-client-state-separate
data
and then pass it as a prop to a separate Form
component. you can control it with a key as described in this article. This is okay, but you can't benefit from background updates (which is okay for forms, so you can turn them off with staleTime: Infinity
)I have forked your sandbox to show the second approach: https://codesandbox.io/s/cool-framework-zrw0i
great post (and blog), thanks!
Once could also argue that the scope of the draft email state is now too big. Why does the App even care about that, it probably only cares about the new email once the user hits Apply.
I think the first word should "One", no?
@chiptus yep. if you want to, you can open a PR?
Putting props to useState | TkDodo's blog
Part deux of the useState pitfalls series is here, showing patterns to help solve the common use-case of initializing state with a prop.
https://tkdodo.eu/blog/putting-props-to-use-state