React.js Fundamental concepts Part 2
By NTh Hai - 10 min read
Fundamental #6: Every React component has a story
The following applies to the class component only (those that extend React.Component). Function components have a slightly different story.
- First, we define a template for React to create elements from the component.
- Then, we instruct React to use it somewhere. For example, inside a render call of another component, or with ReactDOM.render.
- Then, React instantiates an element and gives it a set of props that we can access with this.props. Those props are exactly what we passed in step 2 above.
- Since it’s all JavaScript, the constructor method will be called (if defined). This is the first of what we call: component lifecycle methods.
- React then computes the output of the render method (the virtual DOM node).
- Since this is the first time React is rendering the element, React will communicate with the browser (on our behalf, using the DOM API) to display the element there. This process is commonly known as mounting.
- React then invokes another lifecycle method, called componentDidMount. We can use this method to, for example, do something on the DOM that we now know exists in the browser. Prior to this lifecycle method, the DOM we work with was all virtual.
- Some components stories end here. Other components get unmounted from the browser DOM for various reasons. Right before the latter happens, React invokes another lifecycle method, componentWillUnmount.
- The state of any mounted element might change. The parent of that element might re-render. In either case, the mounted element might receive a different set of props. React magic happens here and we actually start needing React at this point! Prior to this point, we did not need React at all, honestly. The story of this component continues, but before it does, we need to understand this state thing that I speak of.
Fundamental #7: React components can have a private state
The following is also only applicable to class components. Did I mention that some people call presentational-only components dumb?
The state property is a special one in any React class component. React monitors every component state for changes. But for React to do so efficiently, we have to change the state field through another React API thing that we need to learn, this.setState:
// Example 13 - the setState API
// https://jscomplete.com/repl?j=H1fek2KH-
class CounterButton extends React.Component {
state = {
clickCounter: 0,
currentTimestamp: new Date(),
};
handleClick = () => {
this.setState((prevState) => {
return { clickCounter: prevState.clickCounter + 1 };
});
};
componentDidMount() {
setInterval(() => {
this.setState({ currentTimestamp: new Date() })
}, 1000);
}
render() {
return (
<div>
<button onClick={this.handleClick}>Click</button>
<p>Clicked: {this.state.clickCounter}</p>
<p>Time: {this.state.currentTimestamp.toLocaleString()}</p>
</div>
);
}
}
// Use it
ReactDOM.render(<CounterButton />, mountNode);
This is the most important example to understand. It will basically complete your fundamental knowledge of the React way. After this example, there are a few other small things that you need to learn, but it’s mostly you and your JavaScript skills from that point.
Let’s walk through Example 13, starting with class fields. It has two of them. The special state field is initialized with an object that holds a clickCounter that starts with 0, and a currentTimestamp that starts with new Date().
The second class field is a handleClick function, which we passed to the onClick event for the button element inside the render method. The handleClick method modifies this component instance state using setState. Take notice of that.
The other place we’re modifying the state is inside an interval timer that we started inside the componentDidMount lifecycle method. It ticks every second and executes another call to this.setState.
In the render method, we used the two properties we have on the state with a normal read syntax. There is no special API for that.
Now, notice that we updated the state using two different ways:
- By passing a function that returned an object. We did that inside the handleClick function.
- By passing a regular object. We did that inside the interval callback.
Both ways are acceptable, but the first one is preferred when you read and write to the state at the same time (which we do). Inside the interval callback, we’re only writing to the state and not reading it. When in doubt, always use the first function-as-argument syntax. It’s safer with race conditions because setState should always be treated as an asynchronous method.
How do we update the state? We return an object with the new value of what we want to update. Notice how in both calls to setState, we’re only passing one property from the state field and not both. This is completely okay because setState actually merges what you pass it (the returned value of the function argument) with the existing state. So, not specifying a property while calling setState means that we wish to not change that property (but not delete it).
Fundamental #8: React will react
React gets its name from the fact that it reacts to state changes (although not reactively, but on a schedule). There was a joke that React should have been named Schedule!
However, what we witness with the naked eye when the state of any component gets updated is that React reacts to that update and automatically reflects the update in the browser DOM (if needed).
Think of the render function’s input as both:
- The props that get passed by the parent
- The internal private state that can be updated anytime
When the input of the render function changes, its output might change.
React keeps a record of the history of renders and when it sees that one render is different than the previous one, it’ll compute the difference between them and efficiently translate it into actual DOM operations that get executed in the DOM.
Fundamental #9: React is your agent
You can think of React as the agent we hired to communicate with the browser. Take the current timestamp display above as an example. Instead of us manually going to the browser and invoking DOM API operations to find and update the p#timestamp element every second, we just changed a property on the state of the component and React did its job of communicating with the browser on our behalf. I believe this is the true reason why React is popular. We hate talking to Mr. Browser (and the so many dialects of the DOM language that it speaks) and React volunteered to do all the talking for us, for free.
Fundamental #10: Every React component has a story (part 2)
Now that we know about the state of a component and how when that state changes some magic happens, let’s learn the last few concepts about that process.
- A component might need to re-render when its state gets updated or when its parent decides to change the props that it passed to the component
- If the latter happens, React invokes another lifecycle method, componentWillReceiveProps.
- If either the state object or the passed-in props are changed, React has an important decision to do. Should the component be updated in the DOM? This is why it invokes another important lifecycle method here, shouldComponentUpdate. This method is an actual question, so if you need to customize or optimize the render process on your own, you have to answer that question by returning either true or false.
- If there is no custom shouldComponentUpdate specified, React defaults to a very smart thing that’s actually good enough in most situations.
- First, React invokes another lifecycle method at this point, componentWillUpdate. React will then compute the new rendered output and compare it with the last rendered output.
- If the rendered output is exactly the same, React does nothing (no need to talk to Mr. Browser).
- If there is a difference, React takes that difference to the browser, as we’ve seen before.
- In any case, since an update process happened anyway (even if the output was exactly the same), React invokes the final lifecycle method, componentDidUpdate. Lifecycle methods are actually escape hatches. If you’re not doing anything special, you can create full applications without them. They’re very handy for analyzing what is going on in the application and for further optimizing the performance of React updates.