React onClick事件中useState状态读取值异常问题排查与修复
问题现象
界面效果如下:
复现步骤:先点击第一个按钮触发状态更新,再点击第二个按钮读取状态值,此时控制台输出channel值为1,但预期输出值应为2(已通过setChannel将值设置为2)。
示例代码如下:
import { StrictMode } from "react"; import { createRoot } from "react-dom/client"; import React, { useState, useEffect, useMemo, useRef, useCallback } from "react"; const App = () => { const [channel, setChannel] = useState(null); const handleClick = useCallback(() => { console.log(channel); }, [channel]); const parentClick = () => { console.log("parent is call"); setChannel(2); }; useEffect(() => { setChannel(1); }); return ( <div className="App"> <button onClick={parentClick}>Click to SetChannel 2</button> <button onClick={handleClick}>Click to ShowChannel 2</button> </div> ); }; const rootElement = document.getElementById("root"); const root = createRoot(rootElement); root.render(<App />);
产生原因
问题根源是useEffect没有传依赖数组,这种写法会让effect在每次组件重渲染完成后都执行一次:
- 组件首次挂载完成,useEffect执行,调用
setChannel(1)触发重渲染,此时channel更新为1,依赖channel的handleClick也随之更新,内部捕获的channel值为1 - 点击第一个按钮调用
setChannel(2),组件再次重渲染,重渲染完成后这个无依赖的useEffect会立刻再次执行,直接把channel的值重置回1 - 之后点击第二个按钮触发
handleClick,读到的自然就是被重置后的1,和预期的2不符
修复方法
给这个useEffect传入空依赖数组,让它只在组件首次挂载时执行一次,不会在后续重渲染时重复触发即可:
useEffect(() => { setChannel(1); }, []); // 空依赖数组:仅组件挂载阶段执行一次
修复后执行逻辑:
- 组件首次挂载,useEffect执行设置channel为1
- 点击第一个按钮设置channel为2,重渲染阶段useEffect不会重复执行,channel值保持为2
- 点击第二个按钮时控制台输出2,符合预期
内容的提问来源于stack exchange,提问作者william007
相关产品推荐
相关产品推荐

