TkDodo / blog-comments

6 stars 1 forks source link

blog/putting-props-to-use-state #11

Closed utterances-bot closed 2 years ago

utterances-bot commented 4 years ago

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

hrafnkellpalsson commented 3 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!

YagamiNewLight commented 3 years ago

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"

TkDodo commented 3 years ago

@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 :)

YagamiNewLight commented 3 years ago

Many thanks, I got the point. I very like your blogs, I can learn much from it. :p

gezichenshan commented 3 years ago

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.

TkDodo commented 3 years ago

@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.

gezichenshan commented 3 years ago

@TkDodo yeah, I got it. I mixed the concept of re-render and re-mount. Thanks!

OkoloJohnbosco commented 3 years ago

@TkDodo how would u force react to re-mount a child component?

TkDodo commented 3 years ago

@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

OkoloJohnbosco commented 3 years ago

Thank you

bartzy commented 3 years ago

I'm not sure I completely agree:

  1. 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.

  2. 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!

TkDodo commented 3 years ago

@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 :)

andrew-hu368 commented 2 years ago

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).

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?

TkDodo commented 2 years ago

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

I have forked your sandbox to show the second approach: https://codesandbox.io/s/cool-framework-zrw0i

chiptus commented 2 years ago

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?

TkDodo commented 2 years ago

@chiptus yep. if you want to, you can open a PR?

https://github.com/tkdodo/blog