One of the big things the React team announced as part of React 15.5 and React 16 is that the old React.createClass
approach for creating components is no longer recommended:
var Foo = React.createClass({
render: function() {
return (
<h1>Hello!</h1>
);
}
});
The approach instead is to use the class syntax:
class Foo extends React.Component {
render() {
return (
<h1>Hello!</h1>
);
}
}
Overall, this change is fine! It’s time we all moved to use the class-based syntax anyway. There is one major annoyance, though. When using createClass
, React autobinds function to the component. This allows you to access the component via this.componentName
. With the class approach, you don’t get autobinding. You have to bind functions and other things you care about manually…like an animal!
Here is an example:
class LightningCounter extends React.Component {
constructor(props) {
super(props);
this.state = {
strikes: 0
};
}
timerTick() {
this.setState({
strikes: this.state.strikes + 100
});
}
componentDidMount() {
setInterval(this.timerTick, 1000);
}
render() {
return (
<h1>{this.state.strikes}</h1>
);
}
}
class LightningCounterDisplay extends React.Component {
render() {
var divStyle = {
width: 250,
textAlign: "center",
backgroundColor: "black",
padding: 40,
fontFamily: "sans-serif",
color: "#999",
borderRadius: 10
};
return(
<div style={divStyle}>
<LightningCounter/>
</div>
);
}
}
ReactDOM.render(
<LightningCounterDisplay/>,
document.querySelector("#container")
);
This is the code behind the Dealing with State tutorial. When the code runs, in an ideal world, the timerTick
function will get called and the code inside it will execute. Reality is that the timerTick
function gets called. The this.state
and other things inside it have no idea what they are bound to. They will return undefined errors when you try to use them.
There are two solutions that you can use that don’t require additional 3rd party libraries. One solution is where you explicitly bind timerTick
in the constructor:
class LightningCounter extends React.Component {
constructor(props) {
super(props);
this.state = {
strikes: 0
};
this.timerTick = this.timerTick.bind(this);
}
.
.
.
}
One other solution, is to use arrow functions:
timerTick = () => {
this.setState({
strikes: this.state.strikes + 100
});
}
Both of these approaches will get your code to work. The value of this
will be bound properly and all the properties you try to access will resolve correctly.
If you want a more automated solution that relies on another library, then react-autobind might be up your alley: https://www.npmjs.com/package/react-autobind
With all of this said, this is a step backwards compared to React.createClass
. There are ways to handle this automatically as part of the React library. Or maybe there isn’t. Who knows
Cheers,
Kirupa