You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React Hook setState搭配react-hook-popup使用时状态无法更新问题

问题原因

react-hook-popup的usePopup Hook在组件首次渲染时就会注册弹窗的渲染函数,该函数形成的闭包只会捕获首次渲染时的状态变量值,后续组件状态更新时,弹窗内部的渲染函数不会同步更新,所以你看到的永远是初始的newChore和newChoreIndex值,只有重新调用showPopup时才会传入最新的参数。

解决方案
  • 方案1:将弹窗需要用到的状态通过showPopup参数传入,把弹窗变成无状态组件
    所有弹窗内需要的状态都在调用showPopup的时候作为参数传递,修改弹窗渲染函数只接收参数不直接引用组件的状态:
// 弹窗定义
const [showPopup, hidePopup] = usePopup('popup', ({ message, newChoreIndex, newChore, handleClose, onChoreChange, onUpdate }) => (
    <div className="modal">
        <div className="modalInner">
            <button 
                className="modalClose"
                onClick={handleClose}>
                X
            </button>
            <div className="modalInner2">
                <p className="modalHeading">Previous Chore(s)</p>
                <p className="modalChore">{message}</p>
                <p className="modalHeading">New Chore {newChoreIndex}</p>
                <input
                    className="newChoreInput"
                    placeholder="New Chore"
                    value={newChore}
                    onChange={(e) => onChoreChange(e.target.value)}
                />
                <button 
                    className="modalSubmit"
                    onClick={() => {
                        onUpdate()
                        hidePopup()
                    }}>
                    Update Chore
                </button>
            </div>
        </div>
    </div>
));

// 调用showPopup的时候传入所有需要的参数
onClick={() => {
    setNewChoreIndex(index)
    setNewChore('') // 打开编辑前重置输入
    showPopup(item, newChoreIndex, newChore, (val)=>setNewChore(val), updateChore)
}}
  • 方案2:放弃使用react-hook-popup,改用受控组件实现弹窗
    直接在组件内用状态控制弹窗显示隐藏,这样弹窗内部可以直接访问最新的组件状态,不需要额外处理闭包问题:
// 新增弹窗显示状态
const [popupVisible, setPopupVisible] = useState(false)
const [currentChore, setCurrentChore] = useState('')

// 渲染弹窗部分直接写在返回的JSX里,根据popupVisible控制显示
{popupVisible && <div className="modal">
    {/* 弹窗内容和之前一样,直接引用newChore、newChoreIndex即可 */}
</div>}

// 打开弹窗的逻辑
onClick={() => {
    setNewChoreIndex(index)
    setNewChore('')
    setCurrentChore(item)
    setPopupVisible(true)
}}

该方案逻辑更简单,也不会有闭包陷阱,适合对React Hooks不熟悉的场景。

  • 方案3:使用useRef存储状态变量
    如果一定要用react-hook-popup,可以把需要在弹窗内访问的状态存到ref里,ref的current属性是可变的,不会受闭包影响:
const [newChore, _setNewChore] = useState("")
const newChoreRef = useRef(newChore)
const setNewChore = (val) => {
    _setNewChore(val)
    newChoreRef.current = val
}
const [newChoreIndex, _setNewChoreIndex] = useState(-1)
const newChoreIndexRef = useRef(newChoreIndex)
const setNewChoreIndex = (val) => {
    _setNewChoreIndex(val)
    newChoreIndexRef.current = val
}

// 弹窗内访问ref的current值
<p className="modalHeading">New Chore {newChoreIndexRef.current}</p>
<input
    className="newChoreInput"
    placeholder="New Chore"
    onChange={(e) => {setNewChore(e.target.value)}}
/>

内容的提问来源于stack exchange,提问作者Hossam Alsheikh

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.26 02:15:05