【问题标题】:state is not updating when the component re renders?组件重新渲染时状态不更新?
【发布时间】:2023-03-09 14:27:01
【问题描述】:

我正在制作一个 Nextjs 抽认卡应用。我正在传递这样的甲板结构:

const deck = {
  title: 'React 101',
  flashcards: [flashcardOne, flashcardTwo],
};

作为Deck 组件的道具。该组件显示抽认卡中的第一张卡片和一个“下一步”按钮以增加索引并显示抽认卡中的下一张卡片。 Card 组件非常简单,根据状态front 显示卡片的正面和背面。

这是我到目前为止得到的,它正在工作,但如果我在卡片显示答案 (flashcard.back) 时单击“下一步”,下一张卡片将与答案一起出现。而且我不确定为什么,当我单击“下一步”时,Card 组件不是重新呈现吗?如果组件重新渲染,front 会被设置为 true 吗?

export default function Deck({ deck }) {
  const [cardIndex, setCardIndex] = useState(0);
  const { title, flashcards } = deck;
  return (
    <div className={styles.container}>
      <main className={styles.main}>
        <h1 className={styles.title}>{title}</h1>

        {cardIndex < flashcards.length ? (
          <>
            <div className={styles.grid}>
              <Card flashcard={flashcards[cardIndex]} />
            </div>
            <button onClick={() => setCardIndex((cardIndex) => cardIndex + 1)}>
              Next
            </button>
          </>
        ) : (
          <>
            <div>End</div>
            <button>
              <Link href='/'>
                <a>Go to Home</a>
              </Link>
            </button>
            <button onClick={() => setCardIndex(0)}>Play again</button>
          </>
        )}
      </main>
    </div>
  );
}

export function Card({ flashcard }) {
  const [front, setFront] = useState(true);
  return (
    <>
      {front ? (
        <div
          className={`${globalStyles.card} ${styles.card}`}
          onClick={() => setFront(false)}
        >
          <p className={styles.front}>{flashcard.front}</p>
        </div>
      ) : (
        <div
          className={`${globalStyles.card} ${styles.card}`}
          onClick={() => setFront(true)}
        >
          <p className={styles.back}>{flashcard.back}</p>
        </div>
      )}
    </>
  );
}

【问题讨论】:

    标签: reactjs


    【解决方案1】:

    当状态改变时,卡片会重新渲染,但不会重新挂载。因此,现有状态不会被重置。

    当抽认卡道具发生变化时调用setFront(true)

    const [front, setFront] = useState(true);
    useLayoutEffect(() => {
      setFront(true);
    }, [flashcard]);
    

    我使用useLayoutEffect 而不是useEffect 来确保尽快设置front,而不是在绘制周期之后(这可能会导致闪烁)。

    您还可以显着瘦身 Card JSX:

    export function Card({ flashcard }) {
      const [front, setFront] = useState(true);
      const face = front ? 'front' : 'back';
      return (
        <div
          className={`${globalStyles.card} ${styles.card}`}
          onClick={() => setFront(!front)}
        >
          <p className={styles[face]}>{flashcard[face]}</p>
        </div>
      );
    }
    

    【讨论】:

    • 天啊!我只是想找到我的代码参考!哈哈。谢谢,现在我对useLayoutEffect有所了解!
    • globalStyles.card + " " + styles.card 小于 `${globalStyles.card} ${styles.card}` 对吧?
    • 两者都可以正常工作,无论哪种方式,语法对我来说都不错。一种可以连接,也可以使用模板文字。
    • 感谢您的回答。一个问题,应该是onClick= {() =&gt; setFront((prevOpen) =&gt; !prevOpen)} ?
    • @saralance 这也可以,但没必要。因为此时外部的front 变量是可见的,所以您可以使用setFront(!front),对吧?
    【解决方案2】:

    好的,我想我也遇到了同样的问题。由于您正在使用功能组件,并且您正在重新使用相同的组件,或者更确切地说,您并没有真正卸载和重新安装组件,您只是在更改道具,这种情况发生了。为此,您需要先执行useEffect(),然后执行setFront(true)

    这是我在应用中使用的代码。

      useEffect(() => {
        setFront(true);
      }, [flashcard]);
    

    这是我在Word.js 文件中使用的内容。

    【讨论】:

      猜你喜欢
      • 2018-06-05
      • 2020-10-24
      • 2019-10-06
      • 2019-06-17
      • 1970-01-01
      • 2020-11-04
      • 2021-05-19
      • 2019-10-11
      相关资源
      最近更新 更多