为什么 React 在状态改变后不渲染? 【功能组件】

时间:2021-03-23 18:18:20

标签: javascript reactjs react-functional-component

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>)
  }
}

所以我试图在反应中制作一个 Memory_Card_Game 但是当我洗牌图像数组时(当用户点击图像时)这是一个状态变量。 React 不渲染。我在文档中阅读了当组件状态发生变化时,react 会更新虚拟 DOM 树。为什么更改图像数组后不呈现?

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

4 个答案:

答案 0 :(得分:1)

您正在改变原始图像数组。

您设置 newImages = images(这只是一个参考而不是副本),然后更改 newImages 中的位置。

这有效地改变了原始数组,因此当 react 将传递给 setImages 的 newImages 与之前的图像进行比较时,它们是相同的数组,因此没有检测到任何变化。

您可以使用 let newImages = [...images];

修复它

答案 1 :(得分:0)

React 使用 Object.is 比较算法来检查状态变量的变化,在这种情况下,images 是一个 Array,所以与其就地改变它的值,你应该创建每次一个新的,例如:

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

答案 2 :(得分:0)

您的 newImages 数组基本上是相同的数组(相同的引用)。试试这个:

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);
  }

通过这种方式,我们创建了图像数组的副本。

答案 3 :(得分:0)

由于您正在改变数组并使用数组的相同引用设置状态,因此反应选择不重新渲染组件。发生这种情况是因为 React 在检查 setState 之后是否需要重新渲染时使用 Object.is 比较。这个想法是返回数组的新引用而不是改变原始数组。您可以通过使用扩展语法浅复制原始数组来使其工作

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);
  }