Setting Initial State
A React component can access dynamic information in two ways: props and state
Unlike props, a component's state is not passed in from the outside. A component decides its own state.
To make a component have state, give a component a state property. The state property should be declared inside of a constructor method.:
class Example extends React.Component {
constructor(props) { // constructor method
super(props);
this.state = { mood: 'decent' }; // state property
}
render() {
return <div></div>;
}
}
<Example />
this.state = {}
This object represents the initial state of any component instance.
constructor() and super() are both features of ES6, not unique to React. More on them here and here.
Accessing a Component's state
To read a component's state, use the expression this.state.name-of-property
class TodayImFeeling extends React.Component {
constructor(props) {
super(props);
this.state = { mood: 'decent' };
}
render() {
return (
<h1>
I'm feeling {this.state.mood}!
</h1>
);
}
}
Updating state with this.setState
A component can do more than just read its own state, it can also change its own state.
this.setState()
Takes two arguments: an _object _that will update the component's state and a callback. (You basically never need the callback)
this.setState({ hungry: true })
this.setState() takes an object and merges that object with the component's current state.
{
hungry: true,
mood: 'great'
}
Call this.setState from Another Function
The most common way to call this.setState() is to call a function that wraps a this.setState() call.
toggleMood() is the wrapper function below:
import React from 'react';
import ReactDOM from 'react-dom';
class Mood extends React.Component {
constructor(props) {
super(props);
this.state = { mood: 'good' };
this.toggleMood = this.toggleMood.bind(this);
}
toggleMood() {
const newMood = this.state.mood == 'good' ? 'bad' : 'good';
this.setState({ mood: newMood });
}
render() {
return (
<div>
<h1>I'm feeling {this.state.mood}!</h1>
<button onClick={this.toggleMood}>
Click Me
</button>
</div>
);
}
}
ReactDOM.render(<Mood />, document.getElementById('app'));
Here is how <Mood />'s state would be set:
- A user triggers an
onClickby clicking a<button>. - When this listened-for event occurs, it calls an event handler function
this.toggleMood() - Inside the body of the event handler,
this.setState()is called - The component's
stateis changed!
.bind()
Due to the way that event handlers are bound in JavaScript , this.toggleMood() loses its this when used in <button onClick={this.toggleMood}>. Therefore, whenever you define an event handler that uses this, you need to add this.methodName = this.methodName.bind(this) to your constructor function.
import React from 'react';
import ReactDOM from 'react-dom';
const green = '#39D1B4';
const yellow = '#FFD712';
class Toggle extends React.Component {
constructor(props) {
super(props);
this.state = { color: green };
this.changeColor = this.changeColor.bind(this);
}
changeColor() {
const newColor = this.state.color == green ? yellow : green;
this.setState({ color: newColor });
}
render() {
return (
<div style={{background:this.state.color}}>
<h1>
<button onClick={this.changeColor}>Change color</button>
</h1>
</div>
);
}
}
ReactDOM.render(<Toggle />, document.getElementById('app'));
this.setState() Automatically Calls render()
When the <button> is clicked, it calls changeColor() which calls this.setState() which updates this.state.color.
Since {{background:this.state.color}} is in render(), and this.setState() automatically calls render() the background is magically rendering without having to re-render <Toggle />.