为什么 React 重新渲染我的组件并且不使用 CSS 动画?

问题描述 投票:0回答:1

这是实时网站:https://luxury-stroopwafel-b36b51.netlify.app/ 这是 Github 存储库:https://github.com/FullStackPete/CatMemoryGame

我的动画有问题。当我单击猫的图像时 - 包含猫数据的数组正在被洗牌,然后被重新渲染。所以它是这样的:你点击一只猫 -> 卡片翻转 -> allData 数组正在被洗牌 -> 卡片(应该)以动画方式展开。 但您可能会注意到,只有翻转后具有相同 ID 的卡片才会获得动画效果。所有洗过的牌都会立即“呈现”为

cardIsActive(false)
- 这是我负责翻转牌的状态。当我注释掉
shuffleData(allData);
行时,所有动画都已正确完成,但卡片没有被洗牌,因此游戏没有任何意义。请帮我解决这个问题。

负责翻转的库(虽然我不认为它会引起问题):https://www.npmjs.com/package/react-card-flip

应用程序.jsx

const shuffleData = (array) => {
    for (let i = array.length - 1; i > 0; i--) {
      const j = Math.floor(Math.random() * (i + 1));
      [array[i], array[j]] = [array[j], array[i]];
    }
    return array;
  };
  const handleHowToPlayClick = () => {
    setShowInstructions(!showInstructions);
  };

  const handleCardClick = (data) => {
    setCardIsActive(false);
    setTimeout(()=>{
      setCardIsActive(true);
    },500);
    if (!pickedCards.includes(data.id)) {
      setPickedCards((prev) => [...prev, data.id]);
      setCardsLeft((prev) => prev.filter((item) => item !== data.id));   
      shuffleData(allData);
      
      if (pickedCards.length >= highestWin) {
        setHighestWin(pickedCards.length);        
      }
    } else {
      //Lose Logic
      setLose((prev) => prev + 1);
      setCurrentRound(3);
      setPickedCards([]);
    }
  };

  useEffect(() => {
    
    if (pickedCards.length > highestWin) {
      setHighestWin(pickedCards.length);
    }

    if (cardsLeft.length === 0) {
      setWin((prev) => prev + 1);
      setCurrentRound((prev) => prev + 2);
    }
  }, [cardsLeft]);
return (
//code responsible for rendering - not important
)

Cards.jsx

export function Cards({  handleCardClick,  setAllCards,  setCardsLeft,  lose,  allData,  setAllData,  cardIsActive,  win,  currentRound,
}) {
  const chunkSize = 3; 
  const CatApi = `https://api.thecatapi.com/v1/images/search?limit=${currentRound}&api_key=${
    import.meta.env.VITE_CatApiKey
  }`;
  useEffect(() => {
    const fetchData = async () => {
      try {
        const res = await axios.get(CatApi);
        setAllData(res.data);
        const cardIds = res.data.map((data) => data.id);
        setAllCards(cardIds);
        setCardsLeft(cardIds);
      } catch (err) {
        console.log("Error fetching data: ", err);
      }
    };
    fetchData();
  }, [lose, win]);
  const chunkedData = Array.from(
    { length: Math.ceil(allData.length / chunkSize) },
    (_, index) => allData.slice(index * chunkSize, (index + 1) * chunkSize)
  );
  return (
    <div className="flex flex-col items-center justify-center mt-8">
      {chunkedData.map((chunk, index) => (
        <div className="flex flex-row" key={index}>
          {chunk.map((data) => (            
            <>
              <Tilt
                tiltMaxAngleX="15"
                tiltMaxAngleY="15"
                key={data.id}
                className="!p-0 m-4 background-color  !rounded-xl aspect-[3/4] max-h-60 min-h-60 lg:max-h-80 lg:min-h-80"
              >
                <ReactCardFlip
                  flipDirection="horizontal"
                  isFlipped={cardIsActive}
                >
                  <img
                    onClick={() => handleCardClick()}
                    className="aspect-[3/4] max-h-60 min-h-60 lg:max-h-80 lg:min-h-80 rounded-xl card-shadow hover:cursor-pointer"
                    src={CardBackground}
                  />
                  <img
                    onClick={() => handleCardClick(data)}
                    className="object-cover aspect-[3/4] max-h-60 min-h-60 lg:max-h-80 lg:min-h-80 rounded-md card-shadow hover:cursor-pointer"
                    key={data.id}
                    src={data.url}
                    //
                  />
                </ReactCardFlip>
              </Tilt>
            </>
          ))}
        </div>
      ))}
    </div>
  );
}

reactjs react-hooks react-dom
1个回答
0
投票

这是一个渲染问题。事实证明,在我对数据进行洗牌后,没有后续重新渲染。所以我为此添加了一个特殊状态

 const [render, setRender] = useState(-1);
之后在我的handleCardClick中添加了一些超时:

    const handleCardClick = (data) => {
    setCardIsActive(false);
    if (!pickedCards.includes(data.id)) {
      setPickedCards((prev) => [...prev, data.id]);
      setCardsLeft((prev) => prev.filter((item) => item !== data.id));

        setTimeout(()=>{shuffleData(allData);},100)
      setTimeout(() => {
        setRender((prev) => prev + 1);
      }, 650);
      setTimeout(() => {
        setCardIsActive(true);
      }, 1000);
      if (pickedCards.length >= highestWin) {
        setHighestWin(pickedCards.length);
      }
    } else {
      //Lose Logic
      setCardIsActive(false);
      setLose((prev) => prev + 1);
      setCurrentRound(3);
      setPickedCards([]);
    }
  };
© www.soinside.com 2019 - 2024. All rights reserved.