State
For components to be completely reusable and encapsulated, they must be able to initialize and update their own private data or state.
Consider the class exercise from the Event Listeners section. It was a list with an input field and a button that appended the value of the input field to the list.
Let's rewrite the list in React.
src/List.js
import React, { Component } from 'react';
class List extends Component {
constructor() {
super();
this.state = { list: [] };
this.addToList = this.addToList.bind(this);
this.handleChange = this.handleChange.bind(this);
}
addToList(event) {
event.preventDefault();
const currentList = this.state.list.slice();
currentList.push(this.state.currentValue);
this.setState({ list: currentList, currentValue: '' });
}
handleChange(event) {
const value = event.target.value;
this.setState({ currentValue: value });
}
render() {
// this.state.list is an array of strings; need array of list items
const listItems = this.state.list.map((item, index) => <li key={index}>{item}</li>);
return (
<div>
<ul>
{listItems}
</ul>
<form onSubmit={this.addToList}>
<input type="text" value={this.state.currentValue} onChange={this.handleChange} />
<button>Add to List</button>
</form>
</div>
);
}
}
export default List;
The state
object is initialized in the constructor. Note that super()
must be the first line of the constructor.
The setState
function merges the provided object into the current state.
This leaves other properties of the state
object intact. After merging the provided object into the current state,
it calls the render()
function to learn what should be on the screen then manipulate the DOM accordingly.
Please note how the array of strings is made into an array of JSX list items in the render()
function.
Note that we do not mutate state
directly. As noted in the [React documentation],
we should treat this.state as if it were immutable.
Exercises
Exercise 1
- Create a component that initializes and renders a number.
- Add + and a - buttons to this component.
- The + and - button should increment or decrement the number, respectively.
Exercise 2
- Rename
List.js
toTodoList.js
. - Remove the bullet points from the unordered list.
- Create a new React component:
TodoItem.js
. - The
TodoItem
component should feature a checkbox that, when checked, toggles a boolean nameddone
. - The boolean, when true, will cross out the text of the list. If false, the strikethrough will not exist.
- Instead of mapping the array items to
<li>
tags, map them to<ListItem />
components passing in the appropriateprops
.