Forcing state reset on a React component by using the key prop
Did you know that you can use the key
prop to force reset a component state? Most of the times you want to prevent that, but sometimes it is particularly helpful and helps keeping your code clean.
What is the key prop?
React key
prop is a special prop that can be added to any component in order to explicitly tell React its identity. The common scenario where a component requires a key
prop is within a list: React needs it in order to understand which items have been added, removed or, more generically, modified. This allows for advance DOM manipulations, preventing nodes from being destroyed and recreated for no reason. The key
prop also prevents list items from loosing state between renders.
Key prop works even on non-list components
What it might sounds as a surprise, however, is that the key
prop can be used on any component regardless and if used correctly can solve unwanted state persistency in a really clean way.
For instance, let’s assume that you are building a chat app with a list of rooms on the left and the active room on the right together with a textarea
where the user can write a message:
class App extends React.Component {
state = {
activeChat: null,
}; render() {
return (
<div>
<ChatList
onClick={chat => this.setState({ activeChat: chat })}
/>
<Chat
activeChat={this.state.activeChat}
/>
</div>
);
}
}class ChatList extends React.Component {
// ... implementation
}class Chat extends React.Component {
state = {
message: ''
}; render() {
if(!this.props.activeChat) return null; return (
<div>
{this.props.activeChat.messages.map(m => (
/* render messages */
)}
<textarea value={this.state.message} />
</div>
);
}
}
Whenever the user clicks on a ChatList
item, the App
activeChat
state attribute changes. Based on the current implementation however, when that happens the message
is persisted instead of being reset.
One solution is to define componentWillReceiveProps
, check if activeChat
prop has changed and if so reset the message field manually. This solution works fine, however requires you to be the owner of the component. If Chat
is a component written by someone else with its own state, you might have hard times trying to reset it.
Discarding current component instance
Enters the key
prop: as we said earlier, it helps React identifying a component but it also can be used to tell React that the component identity has changed, forcing a full re-instantiation of that component. Tweaking the example above:
// ...
<Chat
key={this.state.activeChat && this.state.activeChat.id}
activeChat={this.state.activeChat}
/>
Now the state of the Chat
component is bound to activeChat.id
. On activeChat
change, React will discard the current Chat
instance and create a new one with a fresh state.
Be aware of the performance implications
While this is a nice trick that might reduce the complexity of your app, it is important to remember that this approach makes React discard the entire component instance and DOM tree. In the above example, most of the Chat component will be redrawn anyway on activeChat change, so it might be a good enough solution. On real word applications, you should limit non-list components with keys and avoid setting it on top level ones, as it might be the cause of (hard to spot) performance issues.