React hooks:useEffect 未在对象数组上触发

kev*_*vin 3 reactjs react-hooks

为了便于阅读,我将在示例中删除很多功能。然而,本质上我有一个useEffect(如下所示),它具有跟踪state.cards卡对象数组的依赖项。我的假设是,如果该state.cards属性发生变化,则useEffect应该触发。然而,事实并非如此。

以下是正在使用的两种解决方案。我使用第一个,因为它是恒定时间的。第二个虽然很好,但却是线性的。让我困惑的是为什么第二个选项会触发依赖关系,而第一个选项不会。两者都返回正确修改状态的克隆。

不会触发 useEffect 依赖项state.cards

      const newArr = { ...state };
      const matchingCard = newArr.cards[action.payload];   <-- payload = number
      matchingCard.correct += 1;
      matchingCard.lastPass = true;
      return newArr;
Run Code Online (Sandbox Code Playgroud)

确实会触发 useEffect 依赖项state.cards

      const newArr = { ...state };
      const cards = newArr.cards.map((card) => {
        if (card.id === action.payload.id) {
          card.correct += 1;
          card.lastPass = true;
        }
        return card;
      });
      return { ...newArr, cards };
Run Code Online (Sandbox Code Playgroud)

使用效果

  useEffect(() => {
    const passedCards = state.cards.filter((card) => {
      return card.lastPass;
    });
    setLearnedCards(passedCards);
    const calculatePercent = () => {
      return (learnedCards.length / state.cards.length) * 100;
    };
    dispatch({ type: 'SET_PERCENT_COMPLETE', payload: calculatePercent() });
  }, [learnedCards.length, state.cards]);
Run Code Online (Sandbox Code Playgroud)

状态

const initialState = {
  cards: [],  <-- each card will be an object
  percentComplete: 0,
  lessonComplete: false,
};
Run Code Online (Sandbox Code Playgroud)


解决方案:使用第一个示例的工作解决方案:

      const newCardsArray = [...state.cards];
      const matchingCard = newCardsArray[action.payload];
      matchingCard.correct += 1;
      matchingCard.lastPass = true;
      return { ...state, cards: newCardsArray };
Run Code Online (Sandbox Code Playgroud)

原因:扩展数组state.cards会创建该数组的一个新的浅表副本。然后我可以对该克隆数组进行修改并将其作为分配给 的新值返回state.cards。扩展数组有一个新的引用,并且由 检测到useEffect

Chr*_*lus 5

我最好的猜测是,在第二个工作示例中 .map 返回一个带有新引用的新数组。在第一个示例中,您只是更改数组的内容,而不更改对该数组的引用。

我不太确定 useEffect 是如何比较的,但如果我没记错的话,对于一个对象来说,它只是关于该对象的引用。这有时会使在对象上使用 useEffect 变得困难。数组也可能是一样的。

你为什么不尝试一下:

const newCardsArray = [...state.cards]
// do your mutations here
Run Code Online (Sandbox Code Playgroud)

应该使用新的引用复制数组,就像对对象所做的那样。