A common question from React beginners is how to share state between two sibling components. The answer is to Lift the state which basically amounts to finding the lowest common parent shared between the two components and placing the state management there, and then passing the state and a mechanism for updating that state down into the components that need it.
As a community we’re pretty good at doing this and it becomes natural over time. One thing that we typically have trouble remembering to do is to push state back down (or colocate state). In this lesson we’ll learn how to lift state up and push state back down.
Kent C. Dodds: [0:00] Here, we have a simple app component where we are managing some name state so we can pass that to our name component, and pass it to our display component, so that we can render out, "Hey name. You are great."
[0:12] We also have a FavoriteAnimal right here that's managing its own state and rendering the input with the value and onChange handler.
[0:21] Let's say that this Display component, which is a sibling to our FavoriteAnimal component actually needs to know what the animal is, because instead of, "You are great," we want to say, "Your favorite animal is..." and then animal right here.
[0:36] We'll accept that as a prop, but how are we going to get access to that animal, if that state is living in our FavoriteAnimal component? These two are sibling components, so the FavoriteAnimal component can't pass the animal to the Display component.
[0:54] Let's keep on going. We're going to need to accept an animal, and that's going to come from somewhere. We're not sure where yet.
[1:00] From the looks of things, we're going to need to do the same thing to our animal state that we're doing with our name state. That is specifically we need to lift the state from the FavoriteAnimal component to the App component which is the least common parent between these two components.
[1:16] Let's do that. I'm just going to grab this and I'll move that down to right here. Now the FavoriteAnimal doesn't have access to Animal or setAnimal. I'm going to accept animal and onAnimalChange. We'll do the same thing that we did for our name component.
[1:37] OnAnimalChange will be passed to the onChange prop onAnimalChange. The animal gets passed along to the input. Then we come down here to the FavoriteAnimal and we need to pass the animal and onAnimalChange.
[1:54] We'll paste in what we had before. Now, our Display has access to the animal. If we save that then everything should work except this is misspelled. Let's do animal. There we go. Great. Now we can say Mulan and Mulan's favorite animal is a dragon but specifically Mushu.
[2:16] What we did here is what's called lifting state. Typically, you want to have your state as close to the code that's using that state so that's why we have the state in this FavoriteAnimal component. When we had a use case for a sibling component to have access to that state, we have to lift to that state to the least common parent which was this App component.
[2:36] We put it right there and then we passed that state in to the mechanism for updating state which is our setAnimal function as props to the components that need it.
[2:46] Here for our FavoriteAnimal, we're passing the animal prop and onAnimalChange prop so we have a mechanism for updating that state. Then here for the Display, all it needs is the animal so that's all that we passed.
[2:59] Once you learn how to do this, it becomes second nature. One thing we're not quite as good at is pushing state back down or co-locating state. Let's say that our Display use case gets changed and we no longer need to pass the animal down. We're going to say, "You are great!" again. We no longer need this animal prop.
[3:18] Often, people will actually just leave it right there without making any other changes but we need to remember that we no longer need to accept this animal prop on this Display where we're rendering it. Because the animal state is only being used by a single component, that means we can move that state back into that component to get it co-located.
[3:38] Let's move it back up here. We no longer need to accept either one of these props and we can come down here, grab that. Remove both of these props. Then we'll paste that onChange event handler back into our FavoriteAnimal input onChange prop.
[3:55] With that, we've co-located our state making it easier to maintain our application in the long term. In review, what we did here was we explored how to lift a state and then push it back down with state co-location. Our App component here is rendering out some state which does need to be used by multiple elements.
[4:13] Our App is maintaining the name state. We also have this FavoriteAnimal which is maintaining its own state but then our Display component needed to have access to that state so we lifted the animal state up to the least common parent which was our App component.
[4:29] Then we passed that state and a mechanism for updating that state down to the components that needed those things. That was the lifting state part and then we did the reverse to push the state back down for state co-location by moving the state back to where it was before removing the state from the component that doesn't need it anymore, and removing the props that are no longer necessary.
[4:51] This enhances both the performance and the state management maintainability of our application.
I have a problem understanding the concept of ‘least common ancestor.’ The phrasing that works for me is ‘closest common parent,’ as described in this post, https://fjorgedigital.com/insights/blog/the-philosophy-of-react-a-single-source-of-truth/. The diagrams show the necessary relationship and to pass values as props from parent to children.
Can't watch this video. Every 2 seconds it skips 5 seconds ahead