0
import React, {useState, useEffect} from 'react';

import MakeCard from './MakeCard.js';

export default function GameCards(props) {
  const [images, setImages] = useState([{}]);

  // Render component after fetching images
  useEffect(() => {
    getImages(props.cards).then(images => setImages(images));
  }, [props.cards]);

  // shuffle images and update state.
  const shuffleCards = (e) => {
    console.log("clicked");
    let newImages = images;
    for (let i = newImages.length - 1; i >= 0; i--) {
      let temp, j;
      j = Math.floor(Math.random() * i);
      temp = newImages[i];
      newImages[i] = images[j];
      newImages[j] = temp;
    }
    setImages(newImages);
    console.log("newImages: ", images);
  }

  if (images.length === 0) {
    return (<h1>Loading...</h1>)
  } else {
    return (<div>
      {
        images.map((image, i) => <MakeCard image={image} key={i}
          // shuffleCards={shuffleCards} 
        />)
      }
    </div>)
  }
}

So I am trying to make a Memory_Card_Game in react but when I shuffle the image array(when the user clicks on the image) which is a state variable. React does not render. I read in the documentation that react updates the virtual-DOM tree when there is a change in the state of the component. Why it isn't rendering after change in images array ?

const [images, setImages] = useState([{}]);

1
  • I have provided only necessary code. Commented Mar 23, 2021 at 18:19

4 Answers 4

6

You are mutating the original images array.

You set newImages = images (which is just a reference not a copy) and then change positions in newImages.

That effectively changes the original array, and so when react compares the newImages you pass to setImages with the previous images they are the same array and so, no change is detected.

You can fix it with let newImages = [...images];

Sign up to request clarification or add additional context in comments.

1 Comment

Thanks for your answer. I thought assigning the original array to a new variable is fine.
1

Your newImages array is basically the same array(same reference). Try this:

const shuffleCards = (e) => {
    console.log("clicked");
    const newImages = [...images];
    for(let i = newImages.length - 1; i >= 0; i--){
      let temp, j;
      j = Math.floor(Math.random() * i);
      temp = newImages[i];
      newImages[i] = images[j];
      newImages[j] = temp;
    }
    setImages(newImages);
    console.log("newImages: ", images);
  }

This way we create a clone of the image array.

1 Comment

Thanks for answering.
1

Since you are mutating the array and setting the state with the same reference of the array, react chooses to not re-render the component. This happens because React uses Object.is comparison while checking if a re-render neeeds to happens after a setState. The idea is to returns a new reference of the array and not mutate the original array. You can make it work by shallow copying the original array with spread syntax

const shuffleCards = (e) => {
    console.log("clicked");
    // Shallow clone the array
    let newImages = [...images];
    for(let i = newImages.length - 1; i >= 0; i--){
      let temp, j;
      j = Math.floor(Math.random() * i);
      temp = newImages[i];
      newImages[i] = images[j];
      newImages[j] = temp;
    }
    setImages(newImages);
    console.log("newImages: ", images);
  }

2 Comments

Glad to have helped.
Please consider marking the answer as accepted if it helped solve your problem
0

React uses Object.is comparison algorithm to check for change in a state variable, in this case images which is an Array, so instead of changing in place its value, u should create a new one each time, for example:

const newImages = [...images]; // instead of "let newImages = images";

1 Comment

Thanks for your answer.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.