首页 > 解决方案 > 在 React Redux 中使用状态更改来触发模态

问题描述

我正在使用 React Redux 构建游戏,并且我有一个条件,即在发牌时,如果牌超过一定数量,我希望放置一个模态,以便用户可以选择一个丢弃。

我在游戏逻辑中通过将名为“cardHandOverflow”的状态的一部分切换为 true 来执行此操作,并且我希望模态在这种情况下呈现。我为此使用 React Modal 库。

但是我得到了错误

react-dom.development.js:14997 Uncaught Error: Too many re-renders. React limits the number of renders to prevent an infinite loop.

这是我使用的代码:

export const CardHand: React.FC = () => {
  const cardHandOverflow = useSelector((state: RootState) => state.gameStateReducer.players.filter(player => player.id === Player.id)[0].cardHandOverflow);
  
  const [modalIsOpen, setIsOpen] = useState(false);

  const closeModal = () => {
    setIsOpen(false)
  }

  if (cardHandOverflow) {
    setIsOpen(true)
  }

  return (
    <>
      {modalIsOpen ? 
        <DiscardModal 
          modalIsOpen={modalIsOpen} 
          closeModal={closeModal}
          discardableCards={cards}
        /> : null}
    </>
  )

它显然使用 useSelector 和状态更改重新触发创建了某种渲染循环,但是当我将其切换为按钮时,模态渲染良好。我怎样才能获得状态更改以呈现模态一次(所以它的行为就像一个点击事件)?

非常感谢 :-)

标签: reactjsreduxreact-hooksreact-modal

解决方案


这是由setIsOpen(true);何时cardHandOverflow为真。

setIsOpen导致重新渲染,即使值没有改变,并且因为它直接是你的功能组件逻辑的一部分,所以它会在渲染cardHandOverflow为真时运行。

为了避免这些循环,你应该使用 React 提供的钩子,在这种情况下useEffect是最合适的。

export const CardHand: React.FC = () => {
    const cardHandOverflow = useSelector((state: RootState) => state.gameStateReducer.players.filter(player => player.id === Player.id)[0].cardHandOverflow);
    
    const [modalIsOpen, setIsOpen] = useState(false);

    const closeModal = () => {
        setIsOpen(false)
    }

    useEffect(() => {
        if (cardHandOverflow) {
            setIsOpen(true)
        }
    }, [cardHandOverflow, setIsOpen])

    return (
        <>
        {modalIsOpen ? 
            <DiscardModal 
            modalIsOpen={modalIsOpen} 
            closeModal={closeModal}
            discardableCards={cards}
            /> : null}
        </>
    )
}

useEffect只会在组件挂载时以及依赖数组中的值[cardHandOverflow, setIsOpen]更改时运行包含的代码。


推荐阅读