Understanding Referential Equality in React

What is referential equality? Why it is useful to understand, and how referential equality affects component re-rendering in React

In React, state variables are used to render the component state on the browser. When the state changes, React re-renders the component with the new data. It helps keep the user informed of all changes occurring in the application.

However, many React developers do not manage the state variables properly. This results in re-renders not occurring despite the state changing. It will then make an awful user experience in the application.

Therefore, this article will explain how React re-renders a component and what we can do to ensure that the state changes get reflected in the UI smoothly.

How Does React Determine a Component Re-Render?

React re-renders a component only when a change occurs to its state variables or props.

This is shown in the example given below:

const [name, setName] = useState('');
const onButtonClick = (newName: string)=> {
setName(newName);
};

The code snippet displayed above has a method named onButtonClick that updates the state variable – name with a new value.

React compares the new value against the old value for equality using the Object.is() comparison algorithm whenever a new value is assigned to name variable.

If the values are equal, React bails out the re-render. But if the values are different, React triggers a component re-render to reflect the state change.

The Comparison Algorithm — Object.is()

The Object.is() algorithm determines whether two values are the same if:

  1. Both values are undefined or null.
  2. Both values are either true or false.
  3. Both values are Strings having the same characters, length, and order.
  4. Both values are Numbers with the same value or NaN.
  5. Both values are Objects that point to one memory location.

React applies these rules to re-render components whenever a state change is made.

The Comparison Algorithm in Action — Referential Equality

Consider the code shown below to identify how developers can introduce bugs with state management using React to understand Object.is() better.

https://medium.com/media/dc413bd5056fd51ad6f6a13fa4ea60b9/href

The code snippet above shows a state variable named mySelf initialized as an object with properties name and age set to “David” and “30”, respectively. Furthermore, an event listener named changeNameToJohn is declared to change the name to a new value, “John.”

The output of this code is shown below:

Figure 2. Expected output of code snippet

When the button clicks, the name should change to “John” and trigger a re-render to update the UI.

But, currently, it does not happen even-though logging the object displays the updated values, as shown below:

Figure 3. Observing the console after the button gets clicked

Many of you may wonder why the component does not get re-rendered. Looking at the fifth principle of the Object.is() algorithm may help you understand this situation.

Two values are considered equal when both are objects that point to the exact memory location.

With the help of this principle, the bug in the above code can be identified.

const changeNameToJohn = () => {
mySelf.name = "John";
mySelf.age = 30;
console.log(mySelf);
setMySelf(mySelf);
};

During the state change shown above, it assigns the new name to the property of the current object. When the comparison algorithm gets applied by React, the new and current values will still be equal because, behind the scenes, the two values point to the exact memory location.

Therefore, React classifies these values as equal and does not trigger a re-render. Hence, the UI does not reflect the state change.

This process is called Referential Equality, for objects are considered equal based on their memory location and not the values.

Problems with the Referential Equality

Ignoring the Referential Equality introduces minor bugs as discussed above. But, when developing React components, we use effects (useEffect) and memorized callbacks (useCallback) that get triggered only when a value in their dependency array changes.

One minor state management error creates numerous bugs throughout the component in situations like this.

For example, consider the code snippet shown below:

https://medium.com/media/d61be0dcba509ab7a58edb2eb1cfd86c/href

Figure 4 shows an updated version of the first example (figure 1). It contains an effect that executes a method constructTheNameChangeMessage(). It gets wrapped in a callback to return memorized output that changes only when the object mySelf changes (as declared in the dependency array).

The header should change its value when the button clicks, but it doesn’t.

It occurs because of Referential Equality. React applies the Object.is() algorithm and classifies the present mySelf equal with the new value. Therefore, the method – constructTheNameChangeMessage does not return a new memorized version as the values in its dependency array remains unchanged. As a result, the effect does not get executed because the memorized callback does not change.

It introduces a chain of bugs in the code that can negatively affect the user experience. Therefore, it is crucial to address this issue to re-render React components as expected.

Using Referential Equality with React

According to the principle of Object.is(), any two objects pointing to the exact memory location are considered equal. Considering this, implementing the fix is straightforward.

Consider the fix shown below:

const changeNameToJohn = () => {
setMySelf({ ...mySelf, name: 'John' });
}

When the previous code gets replaced with the updated code shown above, we see the output below once the button clicks.

Figure 5. Output of the updated code

Figure 5 shows the state updating and re-rendering successfully as the new state update gets reflected in the UI.

But, what has changed?

When the new event handler is observed, the object — { …mySelf, name: ‘John’} gets passed directly into the method – setMySelf to update the state. By doing so, a new object gets passed into the method rather than updating the existing object.

Therefore, when React applies the Object.is() algorithm, the value that gets passed is not equal to the current value stored in mySelf because the new object points to another memory location. As a result, it causes the state to get updated, creating a chain reaction within the React ecosystem.

This state update will:

  1. Make React return a new memorized output of constructTheNameChangeMessage because the values declared in its dependency array change.
  2. Cause React to execute the effect -useEffect as the callback returned a new memorized output.
  3. Re-render the component to reflect the new state.

Since the state gets successfully rendered on the user interface, it helps keep the user informed of all changes in the application allowing it to function as expected.

Build composable web applications

Don’t build web monoliths. Use Bit to create and compose decoupled software components — in your favorite frameworks like React or Node. Build scalable and modular applications with a powerful and enjoyable dev experience.

Bring your team to Bit Cloud to host and collaborate on components together, and speed up, scale, and standardize development as a team. Try composable frontends with a Design System or Micro Frontends, or explore the composable backend with serverside components.

Give it a try →

https://cdn-images-1.medium.com/max/800/1*ctBUj-lpq4PZpMcEF-qB7w.gif

Conclusion

It is essential to understand where objects get stored in memory and how React determines when to re-render a component in dealing with component rendering.

Therefore, in cases where components don’t get re-rendered when their state gets updated, a fix is to ensure that the objects are not referentially equal (both objects point to different memory locations). It will help prevent unnecessary bugs and help create applications faster.

The code utilized in this article is accessible in my GitHub repository.

I do hope you have found this article helpful. Thank you for reading.

Learn More


Understanding Referential Equality in React was originally published in Bits and Pieces on Medium, where people are continuing the conversation by highlighting and responding to this story.


This content originally appeared on Bits and Pieces - Medium and was authored by Lakindu Hewawasam

What is referential equality? Why it is useful to understand, and how referential equality affects component re-rendering in React

In React, state variables are used to render the component state on the browser. When the state changes, React re-renders the component with the new data. It helps keep the user informed of all changes occurring in the application.

However, many React developers do not manage the state variables properly. This results in re-renders not occurring despite the state changing. It will then make an awful user experience in the application.

Therefore, this article will explain how React re-renders a component and what we can do to ensure that the state changes get reflected in the UI smoothly.

How Does React Determine a Component Re-Render?

React re-renders a component only when a change occurs to its state variables or props.

This is shown in the example given below:

const [name, setName] = useState('');
const onButtonClick = (newName: string)=> {
setName(newName);
};

The code snippet displayed above has a method named onButtonClick that updates the state variable - name with a new value.

React compares the new value against the old value for equality using the Object.is() comparison algorithm whenever a new value is assigned to name variable.

If the values are equal, React bails out the re-render. But if the values are different, React triggers a component re-render to reflect the state change.

The Comparison Algorithm — Object.is()

The Object.is() algorithm determines whether two values are the same if:

  1. Both values are undefined or null.
  2. Both values are either true or false.
  3. Both values are Strings having the same characters, length, and order.
  4. Both values are Numbers with the same value or NaN.
  5. Both values are Objects that point to one memory location.

React applies these rules to re-render components whenever a state change is made.

The Comparison Algorithm in Action — Referential Equality

Consider the code shown below to identify how developers can introduce bugs with state management using React to understand Object.is() better.

The code snippet above shows a state variable named mySelf initialized as an object with properties name and age set to "David" and "30", respectively. Furthermore, an event listener named changeNameToJohn is declared to change the name to a new value, "John."

The output of this code is shown below:

Figure 2. Expected output of code snippet

When the button clicks, the name should change to “John” and trigger a re-render to update the UI.

But, currently, it does not happen even-though logging the object displays the updated values, as shown below:

Figure 3. Observing the console after the button gets clicked

Many of you may wonder why the component does not get re-rendered. Looking at the fifth principle of the Object.is() algorithm may help you understand this situation.

Two values are considered equal when both are objects that point to the exact memory location.

With the help of this principle, the bug in the above code can be identified.

const changeNameToJohn = () => {
mySelf.name = "John";
mySelf.age = 30;
console.log(mySelf);
setMySelf(mySelf);
};

During the state change shown above, it assigns the new name to the property of the current object. When the comparison algorithm gets applied by React, the new and current values will still be equal because, behind the scenes, the two values point to the exact memory location.

Therefore, React classifies these values as equal and does not trigger a re-render. Hence, the UI does not reflect the state change.

This process is called Referential Equality, for objects are considered equal based on their memory location and not the values.

Problems with the Referential Equality

Ignoring the Referential Equality introduces minor bugs as discussed above. But, when developing React components, we use effects (useEffect) and memorized callbacks (useCallback) that get triggered only when a value in their dependency array changes.

One minor state management error creates numerous bugs throughout the component in situations like this.

For example, consider the code snippet shown below:

Figure 4 shows an updated version of the first example (figure 1). It contains an effect that executes a method constructTheNameChangeMessage(). It gets wrapped in a callback to return memorized output that changes only when the object mySelf changes (as declared in the dependency array).

The header should change its value when the button clicks, but it doesn’t.

It occurs because of Referential Equality. React applies the Object.is() algorithm and classifies the present mySelf equal with the new value. Therefore, the method - constructTheNameChangeMessage does not return a new memorized version as the values in its dependency array remains unchanged. As a result, the effect does not get executed because the memorized callback does not change.

It introduces a chain of bugs in the code that can negatively affect the user experience. Therefore, it is crucial to address this issue to re-render React components as expected.

Using Referential Equality with React

According to the principle of Object.is(), any two objects pointing to the exact memory location are considered equal. Considering this, implementing the fix is straightforward.

Consider the fix shown below:

const changeNameToJohn = () => {
setMySelf({ ...mySelf, name: 'John' });
}

When the previous code gets replaced with the updated code shown above, we see the output below once the button clicks.

Figure 5. Output of the updated code

Figure 5 shows the state updating and re-rendering successfully as the new state update gets reflected in the UI.

But, what has changed?

When the new event handler is observed, the object — { ...mySelf, name: 'John'} gets passed directly into the method - setMySelf to update the state. By doing so, a new object gets passed into the method rather than updating the existing object.

Therefore, when React applies the Object.is() algorithm, the value that gets passed is not equal to the current value stored in mySelf because the new object points to another memory location. As a result, it causes the state to get updated, creating a chain reaction within the React ecosystem.

This state update will:

  1. Make React return a new memorized output of constructTheNameChangeMessage because the values declared in its dependency array change.
  2. Cause React to execute the effect -useEffect as the callback returned a new memorized output.
  3. Re-render the component to reflect the new state.

Since the state gets successfully rendered on the user interface, it helps keep the user informed of all changes in the application allowing it to function as expected.

Build composable web applications

Don’t build web monoliths. Use Bit to create and compose decoupled software components — in your favorite frameworks like React or Node. Build scalable and modular applications with a powerful and enjoyable dev experience.

Bring your team to Bit Cloud to host and collaborate on components together, and speed up, scale, and standardize development as a team. Try composable frontends with a Design System or Micro Frontends, or explore the composable backend with serverside components.

Give it a try →

https://cdn-images-1.medium.com/max/800/1*ctBUj-lpq4PZpMcEF-qB7w.gif

Conclusion

It is essential to understand where objects get stored in memory and how React determines when to re-render a component in dealing with component rendering.

Therefore, in cases where components don’t get re-rendered when their state gets updated, a fix is to ensure that the objects are not referentially equal (both objects point to different memory locations). It will help prevent unnecessary bugs and help create applications faster.

The code utilized in this article is accessible in my GitHub repository.

I do hope you have found this article helpful. Thank you for reading.

Learn More


Understanding Referential Equality in React was originally published in Bits and Pieces on Medium, where people are continuing the conversation by highlighting and responding to this story.


This content originally appeared on Bits and Pieces - Medium and was authored by Lakindu Hewawasam


Print Share Comment Cite Upload Translate Updates
APA

Lakindu Hewawasam | Sciencx (2022-03-30T07:22:52+00:00) Understanding Referential Equality in React. Retrieved from https://www.scien.cx/2022/03/30/understanding-referential-equality-in-react/

MLA
" » Understanding Referential Equality in React." Lakindu Hewawasam | Sciencx - Wednesday March 30, 2022, https://www.scien.cx/2022/03/30/understanding-referential-equality-in-react/
HARVARD
Lakindu Hewawasam | Sciencx Wednesday March 30, 2022 » Understanding Referential Equality in React., viewed ,<https://www.scien.cx/2022/03/30/understanding-referential-equality-in-react/>
VANCOUVER
Lakindu Hewawasam | Sciencx - » Understanding Referential Equality in React. [Internet]. [Accessed ]. Available from: https://www.scien.cx/2022/03/30/understanding-referential-equality-in-react/
CHICAGO
" » Understanding Referential Equality in React." Lakindu Hewawasam | Sciencx - Accessed . https://www.scien.cx/2022/03/30/understanding-referential-equality-in-react/
IEEE
" » Understanding Referential Equality in React." Lakindu Hewawasam | Sciencx [Online]. Available: https://www.scien.cx/2022/03/30/understanding-referential-equality-in-react/. [Accessed: ]
rf:citation
» Understanding Referential Equality in React | Lakindu Hewawasam | Sciencx | https://www.scien.cx/2022/03/30/understanding-referential-equality-in-react/ |

Please log in to upload a file.




There are no updates yet.
Click the Upload button above to add an update.

You must be logged in to translate posts. Please log in or register.