Converting a function to a class
- Create an ES6 class, with the same name, that extends React.Component.
- Add a single empty method to it called render().
- Move the body of the function into the render() method.
- Replace props with this.props in the render() body.
- Delete the remaining empty function declaration.
function Clock(props) {
return ( <div> <h1>Hello, world!</h1> <h2>It is {props.date.toLocaleTimeString()}.</h2> </div> );
}
changes to
class Clock extends React.Component {
render() {
return ( <div> <h1>Hello, world!</h1> <h2>It is {this.props.date.toLocaleTimeString()}.</h2> </div> );
}
}
Lifecycle of components
There are 3 phases: Mounting, Updating, and Unmounting
4 built-in methods are called, in this order
5 built-in methods are called, in this order
only 1 built-in method
Mounting
means putting elements into the DOM4 built-in methods are called, in this order
- constructor() is called before anything else, when the component is initiated, and it is the natural place to set up the initial state and other initial values. This method is called with the props, as arguments, and you should always start by calling the super(props) before anything else, this will initiate the parent's constructor method and allows the component to inherit methods from its parent (React.Component).
- getDerivedStateFromProps() is called right before rendering the element(s) in the DOM. This is the natural place to set the state object based on the initial props. It takes state as an argument, and returns an object with changes to the state.
- render() is required, and is the method that actually outputs the HTML to the DOM.
- componentDidMount() is called after the component is rendered. This is where you run statements that requires that the component is already placed in the DOM.
Updating
A component is updated whenever there is a change in the component's state or props.5 built-in methods are called, in this order
- getDerivedStateFromProps() still the natural place to set the state object based on the initial props.
- shouldComponentUpdate() you can return a Boolean value that specifies whether React should continue with the rendering or not. The default value is true.
- render() when a component gets updated, it has to re-render the HTML to the DOM, with the new changes.
- getSnapshotBeforeUpdate() you have access to the props and state before the update, meaning that even after the update, you can check what the values were before the update. If this method is present, you should also include the componentDidUpdate() method, otherwise you will get an error.
- componentDidUpdate() is called after the component is updated in the DOM.
Unmounting
when a component is removed from the DOMonly 1 built-in method
- componentWillUnmount() is called when the component is about to be removed from the DOM.
State
- use setState() instead of this.state=
- React may batch multiple setState() calls into a single update for performance. Because this.props and this.state may be updated asynchronously, you should not rely on their values for calculating the next state. Use a different form of setState() that accepts a function rather than an object, to overcome this issue.
this.setState({ counter: this.state.counter + this.props.increment, }); // accepts object
this.setState((state, props) => ({ counter: state.counter + props.increment })); // accepts function
Data in Nested Components
Neither parent nor child components can know if a certain component is
stateful or stateless, and they shouldn’t care whether it is defined as
a function or a class. This is why state is often called
local or
encapsulated. It is not accessible to any
component other than the one that owns and sets it.
A component may choose to pass its state down as props to its child components. This is commonly called a top-down or unidirectional data flow.
A component may choose to pass its state down as props to its child components. This is commonly called a top-down or unidirectional data flow.
<FormattedDate date={this.state.date} />
Lifting State Up
Often, several components need to reflect the same changing data. We
recommend lifting the shared state up to their closest common ancestor
function BoilingVerdict(props) {
if (props.celsius >= 100) { return <p>The water would boil.</p>; }
return <p>The water would not boil.</p>;
}
class TemperatureInput extends React.Component {
constructor(props) {
super(props);
this.handleChange = this.handleChange.bind(this);
}
handleChange(e) { this.props.onTemperatureChange(e.target.value); }
render() {
const temperature = this.props.temperature;
const scale = this.props.scale;
return (
<fieldset>
<legend>Enter temperature in {scaleNames[scale]}:</legend>
<input value={temperature} onChange={this.handleChange} />
</fieldset>
);
}
}
class Calculator extends React.Component {
constructor(props) {
super(props);
this.handleCelsiusChange = this.handleCelsiusChange.bind(this);
this.handleFahrenheitChange = this.handleFahrenheitChange.bind(this);
this.state = {temperature: '', scale: 'c'};
}
handleCelsiusChange(temperature) { this.setState({scale: 'c', temperature}); }
handleFahrenheitChange(temperature) { this.setState({scale: 'f', temperature}); }
render() {
const scale = this.state.scale;
const temperature = this.state.temperature;
const celsius = scale === 'f' ? tryConvert(temperature, toCelsius) : temperature;
const fahrenheit = scale === 'c' ? tryConvert(temperature, toFahrenheit) : temperature;
return (
<div>
<TemperatureInput scale="c" temperature={celsius} onTemperatureChange={this.handleCelsiusChange} />
<TemperatureInput scale="f" temperature={fahrenheit} onTemperatureChange={this.handleFahrenheitChange} />
<BoilingVerdict celsius={parseFloat(celsius)} />
</div>
);
}
}
// Instead of trying to sync the state between different components,
you should rely on the top-down data flow.
// If something can be derived from either props or state, it probably shouldn’t be in the state.
// If something can be derived from either props or state, it probably shouldn’t be in the state.