skip to Main Content

I am using a function that takes an array as input and returns a shuffled array. When i return the shuffled array , the UI is not getting repainted. Code below –

import { useState } from "react";

function App() {
  const [items, setItems] = useState([
    "Amit",
    "Ashok",
    "Alok",
    "Vijay",
    "Kumar",
    "Raju",
  ]);

  console.log("App component is rendered");

  function shuffle(array) {
    let currentIndex = array.length;
    // While there remain elements to shuffle...
    while (currentIndex != 0) {
      // Pick a remaining element...
      let randomIndex = Math.floor(Math.random() * currentIndex);
      currentIndex--;
      // And swap it with the current element.
      [array[currentIndex], array[randomIndex]] = [
        array[randomIndex],
        array[currentIndex],
      ];
    }
    //
    console.log(array);
      return array;
    //return [...array];
  }
  console.log(items);

  return (
    <>
      <button onClick={() => setItems(shuffle(items))}>Shuffle</button>
      {items?.map((item) => (
        <p key={item}>{item}</p>
      ))}
    </>
  );
}

export default App;

If i return the array using the spread operator , the UI is getting rendered again. Can anyone explain what is the reason for this.

2

Answers


  1. When you use the spread operator to return a new array, it creates a new array object with a different reference. React re-renders components when there is a change in state or props. It checks if the reference of the state object has changed. This is why React re-renders the UI when you return the array using the spread operator.

    So re-rendering can happen for two reasons

    • If you directly modify an existing array (i.e., mutate it), the reference to that array remains the same. Since React uses shallow comparison for state updates, it doesn’t detect any changes and therefore doesn’t trigger a re-render.

    • Or if you create a new array using the spread operator (or any other method), a new array with a different reference is created. React detects that the reference to the state object has changed, so it triggers a re-render.

    So instead of returning the array using a spread operator, you can even create a new one like below

    function shuffle(array) {
      let newArray = [...array]; // Create a new array using spread operator
      let currentIndex = newArray.length;
      while (currentIndex !== 0) {
        let randomIndex = Math.floor(Math.random() * currentIndex);
        currentIndex--;
        [newArray[currentIndex], newArray[randomIndex]] = [
          newArray[randomIndex],
          newArray[currentIndex],
        ];
      }
      return newArray; // Return the new array with a different reference
    }
    
    Login or Signup to reply.
  2. React will not detect the change in object in place, instead you need to create an array and let set in state so that react will detect change and re-render.

    let shuffledArray = array.slice();
    or
    let shuffledArray = [...array];

    to create new array.
    add the line and suffle this, then return this suffeled array back.

    import React, { useRef, useState, useEffect } from 'react';
    
    const Suffling = () => {
      const [items, setItems] = useState([
        "Amit",
        "Ashok",
        "Alok",
        "Vijay",
        "Kumar",
        "Raju",
      ]);
      const [changed, setChanged] = useState(false);
    
      console.log("App component is rendered");
    
      function shuffle(array) {
        setChanged(true);
        console.log("Incoming Array:" + array);
        let shuffledArray = array.slice();
        let currentIndex = array.length;
        
        while (currentIndex != 0) {
         
          let randomIndex = Math.floor(Math.random() * currentIndex);
          currentIndex--;
         
          [shuffledArray[currentIndex], shuffledArray[randomIndex]] = [
            shuffledArray[randomIndex],
            shuffledArray[currentIndex],
          ];
        }
        //
        console.table("Output Array:" + shuffledArray);
        
        return shuffledArray;
      }
    
      return (
        <>
         <button onClick={() => setItems(shuffle(items))}>Shuffle</button>
          {changed && items?.map((item) => (
            <p key={item}>{item}</p>
          ))}
        </>
      );
    }
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search