Breaking Change with setState in React 16 Alpha Affecting React Native 43+
Recently, I upgraded the React Native app at Build.com to version 45.1. While testing the app, we discovered an undocumented change to the way that setState
works. This change will affect React Native version 43+ and is due to a change in the React 16 alpha library.
In this post, I’ll describe this breaking change and my efforts to have it fixed.
How did we discover the bug in React?
In our app, we have a component that I’ve (drastically) simplified below:
import React, { Component, } from 'react'; export default class MyComp extends Component { static state = { // some state }; componentWillReceiveProps(nextProps) { this.callback(nextProps); } componentDidMount() { this.setState({ /* change state */ }, this.callback); } callback = (props = this.props) => { // do something with props console.log(props); }; render() { // render some content } }
The important parts to look at are the setState
and callback
functions. callback
accepts a props
object and, if one is not passed in, it defaults to the current props
of the component. This allows it to be used in other places where you may want to use the old props or the new, incoming props.
Prior to the upgrade, this pattern worked as expected.
After the upgrade, the callback
function would print null
.
Due to a change in the React library, any callback function passed to setState
was called with null
, rather than undefined
, as a parameter. This change breaks the pattern above with default parameters (default parameters are only used if the parameter passed in was undefined
).
How did we work around this bug?
The easiest solution was to just add an arrow function wrapper around the callback in setState
:
componentDidMount() { this.setState({ /* change state */ }, () => this.callback(this.props)); }
What is the long term solution to this bug?
After some research, I found a simple solution to the bug. I’ve created a pull request to the React library and you can see it there.
Interestingly, the code I fixed had not changed recently. However, the code that queues and calls the callback functions was changed which exposed this bug.
Since I do not use React for the web, I’m not clear if this bug affects websites also, or if the bug is limited to React Native. The fix that I created would only affect React Native.
Update: I’ve changed the title to reflect that this bug only appears to affect React Native