Saurabh Srivastava | ibcoder.eth
IBCoder | Saurabh Srivastava

IBCoder | Saurabh Srivastava

Why using sort() won't work in React useState()?

Why using sort() won't work in React useState()?

React needs immutable objects to work while sort() method mutates the original object

Saurabh Srivastava | ibcoder.eth's photo
Saurabh Srivastava | ibcoder.eth
·Jul 30, 2021·

3 min read

Subscribe to my newsletter and never miss my upcoming articles

Today I gave Hacker Rank's React Basics Challenge. It was a simultaneous actively of attempting it and pulling my hair out in the second question, as to why the F**K is sorting not working? Thankfully, I remembered JIT as to what I was doing wrong. And so, here I am writing this article to tell you what I was doing wrong.

Let's start with the question first. It was simple sorting feature implementation on button clicks. The default article structure was something similar like this: DefaultQuestion

This was passed into <App /> as props and then from their to <Articles /> as props. So far so good. The sorting buttons were in <App />. On click, some sorting must occur based on the question's logic. In the below image, Assume that <Articles /> is being passed a prop of articles rather than being looped directly.

MyInitialImplementation

So, did you find the issue with the above code? If you have, congratulations! Your basics of JS & React is clear. Regardless, keep on reading to tell me if I am wrong!

As I was wondering what is happening, I noticed that JS sort method doesn't need a new variable to store the sorted result. You can do it but it isn't required. That means it is modifying the original array. This seemed to me the simple case of in-place sorting I learned about while doing CSE.

So, what is in-place sorting? In simple terms, it's when you sort an array [apply algorithm] without requiring additional space in memory, and thus modifying the data in the same memory address.

So take this array of dogs as an example. Here, the dogs array have a reference memory address stored in it. That means, if I store its value in a new variable "cags" and change it, the value of "dogs" output will change. This in CS/Programming is called "shallow copy". Objects in JavaScript are copied in this way. dogs_array_input dogs_array_output

Arrays are also Objects in JS. Therefore, they are copied the same way as well. Primitive data types are copied in the "correct" manner. Meaning, when we copy something, we want a ditto of the "original" with the ability to change the "copy" without affecting "original". new_array

One way is to use the modern JS spread operator. But that won't work in nested object case of ours. It will create shallow copies of 3 objects of dog inside the array of dogs. So, here's a quick solution. JSON.parse() can be used to fix this but know that it won't work for class methods and instances. fix

So, what was the issue with our initial code? It's how react "reacts" to state changes. More importantly, in functional programming paradigm, it's good and often mandated to not change the existing data. Immutability. React uses Object.is for comparing, comparing the pointers/reference.

MyInitialImplementation

Therefore, in our case, the issue was that the original object "articles" is getting mutated by the JS sort() method. This stops the React from 're-rendering' the component. When "sort" button is clicked, the articles object changes. This can be checked by saving the file again to let the hot-reload take its effect and then check the browser display to confirm. Order would have been changed. But then it doesn't re-render due to in-place sorting which mutates the original articles object. The fundamental here is that objects should be immutable for React to re-render the component.

So how did I fix it? I used flag to re-render the component as below. MyFinalImplementation

This way, when the button is clicked, the "f" flag variable gets changed and this in-effect re-renders the <App /> and thus working as needed.

 
Share this