【问题标题】:React JS Hooks - Maximum update depth exceededReact JS Hooks - 超过最大更新深度
【发布时间】:2020-12-31 14:28:44
【问题描述】:

我有以下组件:-

import React, { useState, useEffect } from "react"
import Card from "./Card"

import joker from "../../assets/joker.png"
import goalie from "../../assets/goalie.png"
import defender from "../../assets/defender.png"
import midfielder from "../../assets/midfielder.png"
import attacker from "../../assets/attacker.png"

const CardsBoard = () => {

  const deckLimits = {
    joker: 4, goalkeepers: 12, defenders: 12, midfielders: 12, attackers: 12
  };

  const [ratingObj, setRatingObj] = useState({});
  const [visible1, setVisible1 ] = useState(false);
  const [visible2, setVisible2 ] = useState(false);
  const [deck, setDeck] = useState([]);
  const [deck1, setDeck1] = useState([]);
  const [deck2, setDeck2] = useState([]);
  const [currCardPl1, setCurrCardPl1] = useState({});
  const [currCardPl2, setCurrCardPl2] = useState({});

  useEffect(() => {
    generateDeck();
    distributeCards();
  }, [deck]);


  const startGame = () => {
    //reset decks
    setDeck([]);
    setDeck1([]);x
    setDeck2([]);

    //generate the card’s values
    generateDeck();
    if (deck.length > 0) {
      distributeCards();

      if (currCardPl1 != undefined){
        console.log(currCardPl1);
        //unMask ratings of Player 1
        setVisible1(true);
        setVisible2(false);
      }
    }
  };

  const distributeCards = () => {
      //randomize the deck
      deck.sort(() => Math.random() - 0.5);

      //distribute 26 cards at random when the game start
      const splitDeck1 = deck.slice(0, 26);
      const splitDeck2 = deck.slice(26, 52);
      //add this card to the deck
      splitDeck1.map((card) => {
        setDeck1(deck1 => [...deck1, card]);
      });
      //add this card to the deck
      splitDeck2.map((card) => {
        setDeck2(deck2 => [...deck2, card]);
      });
      
      //queue the first card to Player 1
      setCurrCardPl1(deck1[0]);      
      //queue the first card to Player 2
      setCurrCardPl2(deck2[0]);      
  };

  const generateDeck = () => {
    for (let i = 0; i < deckLimits.joker; i++) {
      generateCard('joker');
    };
    for (let i = 0; i < deckLimits.goalkeepers; i++) {
      generateCard('goalkeeper');
    };
    for (let i = 0; i < deckLimits.defenders; i++) {
      generateCard('defender');
    };
    for (let i = 0; i < deckLimits.midfielders; i++) {
      generateCard('midfielder');
    };
    for (let i = 0; i < deckLimits.attackers; i++) {
      generateCard('attacker');
    };
  }

  const generateCard = item => {
    const card = {
      player: 0,
      image: getImage(item),
      title: item.toUpperCase(),
      ratings: [
        { title: "Handling", rating: "99" },
        { title: "Reflexes", rating: "99" },
        { title: "Defending", rating: "99" },
        { title: "Strength", rating: "99" },
        { title: "Passing", rating: "99" },
        { title: "Flair", rating: "99" },
        { title: "Finishing", rating: "99" },
        { title: "Composure", rating: "99" },
      ],
    }

    //add this card to the deck
    setDeck(deck => [...deck, card]);
  }

  const getImage = item => {
    switch (item) {
      case "joker":
          return joker;
      case "goalkeeper":
          return goalie;
      case "defender":
          return defender;
      case "midfielder":
          return midfielder;
      case "attacker":
          return attacker;
      default:
        break;
    }
  };

  return (
    <div className="container-fluid justify-content-center">
      <div className="row">
        <div className="col-md-6">
          <div>
            <h4>Player 1</h4>
          </div>
          <Card
            cardInfo={currCardPl1}
            showRatings={visible1}
            onClick={ratingObj => setRatingObj(ratingObj)}
          />
        </div>
        <div className="col-md-6">
          <h4>Player 2</h4>
          <Card
            cardInfo={currCardPl2}
            showRatings={visible2}
            onClick={ratingObj => setRatingObj(ratingObj)}
          />
        </div>
      </div>
      <div className="row top-buffer">
        <div className="col-md-12 text-center">
          <button
            id="startGameBtn"
            name="StartGameButton"
            className="btn btn-secondary"
            onClick={() => startGame()}
          >
            START GAME
          </button>
        </div>
      </div>
    </div>
  )
}

export default CardsBoard

我得到了错误:-

Warning: Maximum update depth exceeded. This can happen when a component calls setState inside useEffect, but useEffect either doesn't have a dependency array, or one of the dependencies changes on every render.

我怀疑它必须与多次调用 setState 的提交按钮 (onClick) 相关,但我似乎无法解决问题。

所以我有以下问题:-

  1. 如何修复 onClick()?
  2. 我想点击开始游戏按钮,然后触发generateDeck();distributeCards();,这样我就可以把甲板、甲板1 和甲板2 填满。有没有办法做到这一点?目前我创建了一个useEffect(),它依赖于被填满的甲板,这是用钩子做的正确方法吗?

感谢您的帮助和时间!

【问题讨论】:

  • 一旦你调用generateDeck,它就会改变deck,这将在useEffect中触发一个无限循环。见generateCard
  • 是否有理由将deck 添加到useEffect 依赖项中?您希望在页面加载时更新卡片组吗?如果是这样,也许那个依赖列表应该是[]?

标签: javascript reactjs react-hooks


【解决方案1】:
deck.sort(() => Math.random() - 0.5);

你这里有问题。 将其保存在变量中。否则,您会一直更新状态。

【讨论】:

    【解决方案2】:

    您在 useEffect 挂钩中有 deck 作为依赖项。这意味着generateDeck 将在每次更新卡组时运行。但是,generateDeck 调用 generateCard,后者调用 setDeck。这会导致deck 发生变化,这意味着您陷入了一种无限循环。您应该将 generateDeck 绑定到 onClick 处理程序或其他不会被 deck 更改触发的事件。

    另外,请注意:

    deck.sort(() => Math.random() - 0.5)
    

    调用sort 会直接改变你的状态,这是你在 React 中应该避免的。请改用setDeck(d=&gt;[...d].sort(/* Your sorting function here */)) 之类的方法。

    【讨论】:

    • 如何将 generateDeck() useEffect 绑定到 onClick 处理程序上?
    • 在 useEffect() 中删除对 deck[] 的依赖也会导致我单击 Start Game 按钮 3 次以获取数据。是否可以点击一次并正确加载卡组?
    • 如果您有 generateDeck 函数作为 onClick 处理程序,则在 useEffect 中不需要它。至于需要多次单击按钮,这可能与 generateDeck 不分发卡片的事实有关,除非卡片组的长度大于 0。您可能需要重新考虑这些函数调用的顺序和是什么触发了他们
    • 好的 Danilo 我会给你答案。我将不得不撕开我的代码,然后一步一步地重新构建它。感谢您的帮助
    【解决方案3】:

    您在distrubuteCardsuseEffect 挂钩中使用setDeck(),再次调用distributeCards

      const distributeCards = () => {
      // bla bla
           setDeck(deck => [...deck, card]);
      }   
    

    这导致一直调用钩子。

    useEffect(() => {
        generateDeck();
        distributeCards();
      }, [deck]);
    

    【讨论】:

      猜你喜欢
      • 2019-04-03
      • 2019-05-28
      • 2021-08-31
      • 2019-12-13
      • 2019-12-03
      • 2020-03-26
      • 2020-11-27
      • 1970-01-01
      • 2018-10-30
      相关资源
      最近更新 更多