Note: These notes are taken from Colt steele’s Modern React Bootcamp course
What is State?
Thinking about state
In any sufficiently advanced web application, the user interface has to be stateful.
- logged-in users see a different screen than logged-out users
- clicking “edit profile” opens up a modal (pop-up) window
- sections of a website can expand or collapse, for instance clicking “read more”
The state of the client interface (frontend) is not always directly tied to state on the server.
Why would the server need to know if a modal is open?
State changes
State is designed to constantly change in response to events.
A great way to think about state is to think of games, for instance chess. At any point in time, the board is in a complex state.
Every new move represents a single discrete state change.
What Does State Track?
There are two types of things state on the client/frontend keeps track of:
- UI logic - the changing state of the interface e.g., there is a modal open right now because I’m editing my profile
- business logic - the changing state of data e.g., in my inbox, messages are either read or unread, and this in turn affects how they display.
Vanilla / jQuery State
The way we kept track of state with jQuery was by selecting DOM elements and seeing if they were displayed/hidden, or if they had certain styles or attributes.
1// getting a text input value
2var firstName = $("#firstNameInput").val();
3// setting a text input value
4$("#firstNameInput").val("Michael");
In other words, we were inferring the state of the application from the DOM itself.
React is going to do the opposite!
To review..
State:
- Internal data specific to a component
- Data that changes over time!
React State
In React, state is an instance attribute on a component. It’s always an object (POJO -> Plain old JS Object), since you’ll want to keep track of several keys/values.
1// what is the current state of my component?
2console.log(this.state);
3
4{
5 playerName: "Whiskey",
6 score: 100
7}
Initial State
State should be initialized as soon as the component is created. So we set it in the constructor function:
1class ClickCount extends Component {
2 constructor(props) {
3 super(props);
4 this.state = {
5 numClicks: 0, // start at zero clicks
6 };
7 }
8}
React Constructor Function
If your component is stateless, you can omit the constructor function. If you are building a component with state, you need a standard React constructor
1constructor(props) {
2 super(props);
3 this.state = {
4 /* values we want to track */
5 };
6}
- constructor takes one argument, props
- You must call super(props) at start of constructor, which “registers” your class as a React Component
- Inside the instance methods, you can refer to this.state just like you did this.props
State can be defined using the new public fields syntax
1class ClickCount extends Component {
2 state = { numClicks: 0 };
3 // ...
4}
Notice that it is state, not this.state, when done like this.
Example:
demo/basicExample.js
1class Game extends Component {
2 constructor(props) {
3 super(props);
4 this.state = {
5 player: "Whiskey",
6 score: 0,
7 };
8 }
9
10 render() {
11 return (
12 <div>
13 <h1>Battleship</h1>
14 <p>Current Player: {this.state.player}</p>
15 <p>Score: {this.state.score}</p>
16 </div>
17 );
18 }
19} // end
Changing State
this.setState() is the built-in React method of changing a component’s state.
this.setState({ playerName: "Matt", score: 0 })
- Can call in any instance method except the constructor
- Takes an object describing the state changes
- Patches state object — keys that you didn’t specify don’t change
- Asynchronous!
- The component state will eventually update.
- React controls when the state will actually change, for performance reasons.
- Components re-render when their state changes
demo/click-me/src/Rando.js
1class Rando extends Component {
2 constructor(props) {
3 super(props);
4 this.state = { num: 0 };
5 this.makeTimer();
6 }
7
8 makeTimer() {
9 setInterval(() => {
10 this.setState({
11 num: Math.floor(Math.random() * this.props.maxNum),
12 });
13 }, 1000);
14 }
15
16 render() {
17 return <button>Rando: {this.state.num}</button>;
18 }
19} // end
React Events
State most commonly changes in direct response to some event. In React, every JSX element has built-in attributes representing every kind of browser event. They are camel-cased, like onClick, and take callback functions as event listeners.
1<button
2 onClick={function (e) {
3 alert("You clicked me!");
4 }}
5>
6 Click Me!
7</button>
React Events are a bit of an abstraction on top of regular browser events. They’re called synthetic events, but in practice they behave the same and you don’t have to worry about the abstraction. Check out the React documentation for all types of supported events.
Example : Broken Click
If we’re updating state in response to an event, we’ll have to call a method with this.setState()
:
demo/click-me/src/BrokenClick.js
1class BrokenClick extends Component {
2 constructor(props) {
3 super(props);
4 this.state = { clicked: false };
5 }
6
7 handleClick() {
8 this.setState({ clicked: true });
9 }
10
11 render() {
12 return (
13 <div>
14 <h1>
15 The Button is
16 {this.state.clicked ? "clicked" : "not clicked"}
17 </h1>
18 <button onClick={this.handleClick}>Broken</button>
19 </div>
20 );
21 }
22} // end
this
is back!!
But this is undefined!
- Who is calling handleClick for us?
- React is, on click
- What is it calling it on?
- 🤷 it doesn’t remember to call it on our instance
- The method was called “out of context”
- What do we do?
.bind()
it!
Example : Fixed click
We’ll fix the situation by binding our instance methods in the constructor.
demo/click-me/src/FixedClick.js
1class FixedClick extends Component {
2 constructor(props) {
3 super(props);
4 this.state = { clicked: false };
5 this.handleClick = this.handleClick.bind(this);
6 }
7
8 handleClick() {
9 this.setState({ clicked: true });
10 }
11
12 render() {
13 return (
14 <div>
15 <h1>
16 The Button is
17 {this.state.clicked ? "clicked" : "not clicked"}
18 </h1>
19 <button onClick={this.handleClick}>Fixed</button>
20 </div>
21 );
22 }
23} // end
States vs Props.
State and Props are the most important concepts in React (after knowing what a “component” is).
term | structure | mutable | purpose |
---|---|---|---|
state | POJO {} | yes | stores changing component data |
props | POJO {} | no | stores component configuration |
State as Props
A common pattern we will see over and over again is a stateful (“smart”) parent component passing down its state values as props to stateless (“dumb”) child components.
1class CounterParent extends Component {
2 constructor(props) {
3 super(props);
4 this.state = { count: 5 };
5 }
6 render() {
7 // passing down parent state as a prop to the child
8 return (
9 <div>
10 <CounterChild count={this.state.count} />
11 </div>
12 );
13 }
14}
This idea is generalized in React as “downward data flow”. It means that components get simpler as you go down the component hierarchy, and parents tend to be more stateful than their children.
Further Reading : checkout React Docs . Two other great resources: Props vs State > ReactJS : Prop vs State