Make Controlled React Components with Control Props

Kent C. Dodds
InstructorKent C. Dodds
Share this video with your friends

Social Share Links

Send Tweet

While the state reducer pattern gives users total control over how the state is updated internally to a component, it doesn't allow them to update state arbitrarily. Let's implement the control props pattern (found in built-in components like <input /> through the value prop) to give users complete control over the state of our component.

Instructor: [00:00] Here we have a simple toggle component that renders a switch, which when clicked, will switch the component on and off. What we want to be able to do is synchronize these so that one is turned on, the other is also turned on, and when one is turned off, the other is also turned off.

[00:15] How we want to accomplish this is whenever our on toggle prop is called, it will be called with the current state of on, and will set the state of both on. Then we'll provide that prop to both of our toggle components, and the toggle component should use the prop rather than internal state to determine what the state of on should be.

[00:33] To support this API is remarkably simple -- rather than determining our on state based off of internal state, we'll just get it from props. Now we have exactly what we're looking for.

[00:44] What we really want to do is support both, so that if one of these doesn't have an on prop, it still functions. To support this, we need to determine what the state actually is, whether it's coming from internal state or props.

[00:57] I'm going to create a function called get state, and this will return our current state. We'll say on is this.props.on, not equal to undefined.

[01:07] If it's not undefined, then it's coming from props. Otherwise, it's coming from state.

[01:13] Then in our render, we can call this.getstate.on. With that, we get our supported API. However, there's a further optimization that we can make here.

[01:23] Because this state is controlled, we don't actually need to call this.setstate. In our small example here, it's not really a big deal, but we could actually wind up re-rendering when it's not necessary.

[01:34] We could say if this.props.on is not equal to undefined, then we know that it's controlled. We can call this.props.on toggle with what we suggest the state should be -- the opposite of this.getstate.on.

[01:48] Otherwise, we can call this.setstate like we were before. Just for consistency, we'll call this.getstate.on. Now we're avoiding a potential unnecessary re-render.

[02:01] Because we're repeating ourselves here, let's just refactor this to a simple method called is controlled. That'll take a prop, and will return this.props at that prop.

[02:13] Then we can say this.iscontrolledon, and our API is working. If we remove the on prop from one of these, then it can be toggled individually from the other.