组件重新渲染时状态不更新?

Posted

技术标签:

【中文标题】组件重新渲染时状态不更新?【英文标题】:state is not updating when the component re renders? 【发布时间】:2021-02-26 12:11:17 【问题描述】:

我正在制作一个 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>
      )
    </>
  );

【问题讨论】:

【参考方案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 文件中使用的内容。

【讨论】:

以上是关于组件重新渲染时状态不更新?的主要内容,如果未能解决你的问题,请参考以下文章

React hooks 功能组件防止在状态更新时重新渲染

更新 Redux 存储时反应组件不重新渲染

仅在重新渲染组件时才反应状态更新

高阶组件状态正在正确更新,但接收道具的包装组件不会在状态更改时重新渲染

StencilJS - 更新导致整个组件重新渲染的状态

React Redux Store 更新,但组件不重新渲染