We’re all familiar with the React component lifecycle: Render, Receive Data, Update, and finally Update the DOM. If you have components that render and receive data but never update the DOM, you’ve probably got something wrong.
In this article, I’ll walk through the process of writing a function that will force a re-render of a React component. It’s important to note that you can only use this technique when you know for sure that the component is not being updated in response to an event.
The general idea is that we want to trigger a re-render when we’ve received new data from an API.
Let’s take a look at the basic lifecycle of a React component:
- Render
- Receive data
- Update
- Update the DOM
We’re interested in the last step, so let’s focus on that. We have some data we want to display, and we want to pass that data to the component so that it can display it. We also have some code that will trigger a re-render, but we need to wait until the data is ready.
So how do we accomplish this? Well, we’ll start with the most obvious approach: we’ll trigger a re-render when we receive new data.
Here’s what we want to do:
When we receive new data, we want to trigger a re-render.
This seems pretty straightforward. But what happens if we receive new data before the component has finished rendering?
Let’s say that we’re using the following component:
Here’s what happens if we receive new data before the component has finished rendering:
- Receive new data
- Trigger re-render
- Component has rendered, but new data hasn’t been rendered
Now we’re in trouble. Because we’re receiving new data, the component is going to trigger a re-render, but it’s already rendered. So we’re going to end up with duplicate data.
In order to prevent this, we’ll have to ensure that the component finishes rendering before we trigger the re-render.
How can we ensure that the component finishes rendering before we trigger the re-render? Well, we have two options:
We can either put the new data in the state and then trigger a re-render when the component is mounted.
Or we can simply trigger a re-render when the component is mounted.
With the second approach, the component is still mounted, but we’re still waiting for the component to finish rendering. So the new data is not yet visible. The component doesn’t need to be re-rendered because the data is still the same.
It’s important to note that in both cases, we’ll still have to update the state of the component when the new data arrives. This is important because we want to guarantee that the component is re-rendered when the new data arrives.
So which approach should we use? In most cases, the first one is fine. However, if you have a component that receives data and renders immediately, then you might want to use the second approach. This is because in this case, the component is not yet mounted, and so the new data is not visible.
In other words, if the component is already mounted, then you can use the first approach. But if the component is not yet mounted, then you can use the second approach.
Now that we understand how to update a React component, let’s see how we can actually force the component to re-render.
What is React Re-Renders
React Re-Renders is an experiment to see if we can use React to build websites that work offline, but can still work with real data. This is a new area of React development, and the current version of React doesn’t have support for this kind of thing. So we decided to write a blog post to explain what we’re doing, and hopefully encourage others to come up with similar ideas.
We’ll be sharing the code we’re working on, so if you want to try out some of this stuff, you can clone our repo.
In our case, we’re using React to build a website that loads a bunch of data from a server, then builds the site around that data. So, it’s a lot like a mobile app, except that instead of having to wait for the phone to load the data, we can load it right away.
Here’s how it works:
When the page loads, React will first load the data from the server, and then render the page. That means that any elements you add to the DOM won’t exist yet until the server returns the data. So, if we want to show a map of the United States, we might add an element to the DOM. Then, when the server returns the image, the browser will actually replace that with the image.
The problem is that, because we haven’t rendered the rest of the page, we have no idea what the rest of the page looks like. We might have a header and footer, but we have no idea what the content of the page is going to be.
We can’t do anything to fix this problem because we can’t add any HTML to the page until we know what the page looks like.
That’s where React Re-Renders comes in.
Instead of waiting for the page to load, React Re-Renders takes the data we already have and renders it immediately. So, if we were rendering the United States, it would render the map of the United States, and then the rest of the page would come in.
This approach has some major benefits:
- It gives you real-time feedback as you work
- If you make changes to the page while the data is loading, you can see them immediately.
- You can create new features without worrying about compatibility issues
- You don’t have to worry about whether you’ve broken anything by adding a new feature or changing something in the DOM.
- It’s easier to debug
With React Re-Renders, you can add a debugger statement to see what the current state of the page is, and you can see what the page will look like as soon as it gets the data back from the server. You can use JSX to create reusable components
React Re-Renders uses the same JSX syntax as React, so you can use the same components you use in React.
What is forcing updates on class-based components in react?
React does not force updates on the component unless the props and state of the component are updated. However, if you want to update the state of the component without updating the props and state, you can use refs.
Refs are special properties of a component that are used to access the DOM elements of that component. Using refs, we can keep the DOM element alive while the state of the component changes.
Refs in React are similar to the DOM events in jQuery. In React, refs are called like any other property. They are stored as an attribute on the component. We can use them in the same way we use regular attributes.
When a ref is used, it automatically creates an event listener for the ref. If the ref value changes, the listener is triggered.
For example, here is a simple react component which uses a ref to get the innerHTML of the element.
const MyComponent = (props) => {
const text = document.querySelector(".myText");
const myRef = React.createRef();
return (
{myRef.current &&
{text}
}
);
};
export default MyComponent;
The above component is used as follows:
To update the content of the innerHTML, we use setState() and the refs.
class MyComponent extends React.Component {
constructor(props){
super(props);
this.state = {
html: 'Hello world!'
}
}
componentDidMount(){
this.setState({
html: document.querySelector(".myText").innerHTML
})
}
render() {
return (
{this.state.html}
)
}
}
ReactDOM.render(
,
document.getElementById('root')
);
Let’s see the demo.
This code snippet has a ref:
When we change the state in the component, the ref is updated and we can get the updated state using the ref.
class MyComponent extends React.Component {
constructor(props){
super(props);
this.state = {
html: 'Hello world!'
}
}
componentDidMount(){
this.setState({
html: document.querySelector(".myText").innerHTML
})
}
render() {
return (
{this.state.html}
)
}
}
// This is the ref
ReactDOM.render(,
document.getElementById('root')
);
We can also pass an event handler to the ref to update the state.
{
this.setState({
html: document.querySelector(".myText").innerHTML
})}}>
In this case, if we click on the div, we can see the updated content in the div.
{
this.setState({
html: document.querySelector(".myText").innerHTML
})}}>
In React 15, we added a new lifecycle method called componentDidUpdate. This method is invoked when a component updates and needs to be re-rendered.
For example, if you want to trigger an animation when the value of variable changes, you can do it using componentDidUpdate. The componentDidUpdate() function takes two parameters:
- prevProps: This is the old props. It’s the props that were passed to the component before the update.
- nextProps: This is the new props. It’s the props that are being passed to the component now.
The code would look something like this:
componentDidUpdate(prevProps, nextProps) {
if (this.props.name!== nextProps.name) {
// the name changed so we need to update the state
}
}
This new method allows developers to react to changes in the component without needing to call render(). So why doesn’t React automatically invoke componentDidUpdate whenever there is a change? Because it’s not always clear when a change is necessary.
If a component is being updated because the user is typing into an input field, then there is no need to update the DOM. But what if the change is coming from a function that is part of the component itself? In this case, the component needs to be re-rendered and the DOM needs to be updated.
One of the problems that makes it difficult to determine whether a change should trigger a re-render is that the new props and old props are not always the same. The new props could be completely different than the old props. Or the new props could be the same as the old props, but with some new values. In both cases, the new props will be different than the old props.
When the new props are completely different, React will invoke componentDidUpdate and re-render the component. But what if the new props are the same as the old props, but with some new values? The new props are different, but the component is being updated because of a function that is part of the component. In this case, React doesn’t know that the new props are different. So, it won’t call componentDidUpdate.
React does not know whether a component is updating because of the props or because of a function in the component. So, it doesn’t try to find out. Instead, it just invokes componentDidUpdate and assumes that the component is being updated because of the new props.
What does this mean for the developer?
As mentioned earlier, the new props are not always different than the old props. So, componentDidUpdate might not always be called. If a component is updating because of a function in the component, React doesn’t know that the new props are different than the old props. So, it will not call componentDidUpdate.
The result is that developers are left wondering:
- How do I force React to call componentDidUpdate when the component is updated?
- What if I need to make sure that a certain function in my component is only called when the component updates?
To help solve this problem, React 16 introduces a new lifecycle method called shouldComponentUpdate.