React修改useState变量时如何区分触发源?最佳实践探讨
状态更新后区分触发源的方案分析与最佳实践
两种方案的可行性分析
场景一:仅通过render状态判断触发源
这个方案不可行。两个按钮点击后都将render设为true,状态值完全一致,useEffect无法区分触发来源,没法针对性执行不同方法。
场景二:用await等待setRender完成
这个方案也不可行。setState(包括setRender)是异步操作,但它不返回Promise,不能用await等待状态更新和渲染完成。代码里await setRender(true)会直接跳过等待,立刻执行后续逻辑,此时DOM还未完成更新,达不到“渲染完成后执行”的目的。
最佳实践
根据是否需要等待渲染完成执行逻辑,分两种情况处理:
情况1:不需要等待渲染完成直接执行逻辑
如果doSomething1/doSomething2不依赖更新后的DOM或状态,直接在各自的点击事件中调用即可,无需借助useEffect:
const [render, setRender] = useState(false); function clickBtn(){ setRender(true); doSomething1(); // 直接执行对应逻辑 } function clickBtn2(){ setRender(true); doSomething2(); // 直接执行对应逻辑 }
情况2:必须等待渲染完成后执行逻辑
此时需要记录触发状态更新的来源,推荐两种方式:
方式1:扩展状态存储触发源
把状态从单一布尔值改成对象,同时保存状态值和触发标识:
const [renderState, setRenderState] = useState({ value: false, trigger: null }); function clickBtn(){ setRenderState({ value: true, trigger: 'btn1' }); } function clickBtn2(){ setRenderState({ value: true, trigger: 'btn2' }); } useEffect(() =>{ if (renderState.value) { switch(renderState.trigger) { case 'btn1': doSomething1(); break; case 'btn2': doSomething2(); break; } } },[renderState]);
方式2:用useRef存储触发标识
通过useRef在点击时记录触发源,在useEffect中读取并执行对应逻辑,执行后重置ref避免误判:
const [render, setRender] = useState(false); const triggerRef = useRef(null); function clickBtn(){ triggerRef.current = 'btn1'; setRender(true); } function clickBtn2(){ triggerRef.current = 'btn2'; setRender(true); } useEffect(() =>{ if (render && triggerRef.current) { if (triggerRef.current === 'btn1') { doSomething1(); } else if (triggerRef.current === 'btn2') { doSomething2(); } triggerRef.current = null; // 重置标识,避免后续触发误判 } },[render]);
内容的提问来源于stack exchange,提问作者whitebear
相关产品推荐
相关产品推荐

