How to handle state in React. The missing FAQ.

Osmel Mora
Jul 18, 2016 · 6 min read

Motivation

Frequently Asked Questions.

How does state work?

// Using React.createClass
var Counter = React.createClass({
getInitialState: function() {
return {counter: 0};
},
...
});// Using ES6 classes
class Counter extends React.Component {
constructor(props) {
super(props);
this.state = {counter: 0};
}
...
}
this.setState(data, callback);

What should I keep in React state?

// Don't duplicate data from props in state
// Antipattern
class Component extends React.Component {
constructor(props) {
super(props);
this.state = {message: props.message};
}

render() {
return <div>{this.state.message}</div>;
}
}
// Better exampleclass Component extends React.Component {    
render() {
return <div>{this.props.message}</div>;
}
}
// Don't hold state based on props calculation
// Antipattern
class Component extends React.Component {
constructor(props) {
super(props);
this.state = {fullName: `${props.name} ${props.lastName}`};
}

render() {
return <div>{this.state.fullName}</div>;
}
}
// Better approachclass Component extends React.Component {
render() {
const {name, lastName} = this.props;
return <div>{`${name} ${lastName}`}</div>;
}
}
// Not an antipatternclass Component extends React.Component {
constructor(props) {
super(props);
this.state = {count: props.initialCount};
this.onClick = this.onClick.bind(this);
}

render() {
return <div onClick={this.onClick}>{this.state.count}</div>;
}

onClick() {
this.setState({count: this.state.count + 1});
}
}
// Don't hold state that you don't use for rendering.
// Leads to unneeded re-renders and other inconsistencies.
// Antipattern
class Component extends React.Component {
constructor(props) {
super(props);
this.state = {count: 0};
}

render() {
return <div>{this.state.count}</div>;
}

componentDidMount() {
const interval = setInterval(() => (
this.setState({count: this.state.count + 1})
), 1000);
this.setState({interval});
}
componentWillUnmount() {
clearInterval(this.state.interval);
}
}
//Better approachclass Component extends React.Component {
constructor(props) {
super(props);
this.state = {count: 0};
}

render() {
return <div>{this.state.count}</div>;
}

componentDidMount() {
this._interval = setInterval(() => (
this.setState({count: this.state.count + 1})
), 1000);
}
componentWillUnmount() {
clearInterval(this._interval);
}
}

Is it true that setState( ) is asynchronous?

class Component extends React.Component {
constructor(props) {
super(props);
this.state = {count: 0};
this.onClick = this.onClick.bind(this);
}

render() {
return <div onClick={this.onClick}>{this.state.count}</div>;
}

onClick() {
this.setState({count: this.state.count + 1});
console.log(this.state.count);

}
}
// Calling setState() twice in the same execution context is a bad // practice. It's used here for illustration purposes. Instead use // an atomic update in real code class Component extends React.Component {
constructor(props) {
super(props);
this.state = {count: 0};
}

render() {
return <div>{this.state.count}</div>;
}

componentDidMount() {
this._interval = setInterval(() => {
this.setState({count: this.state.count + 1});
console.log(this.state.count);
this.setState({count: this.state.count + 1});
console.log(this.state.count);

}, 1000);
}
componentWillUnmount() {
clearInterval(this._interval);
}
}

I heard that under certain circumstances calling setState( ) doesn’t trigger a re-render. Which are those circumstances?

Conclusions

React Ecosystem

All about React and its ecosystem