React组件状态未变更却出现额外console.log输出的原因咨询
React 示例问题原因解析
示例1:非StrictMode下重复打印日志
代码:
export const App = (props) => { const [data, setData] = useState(0) console.log(data) const onClick = () => { setData(1) } return <button onClick={onClick}>button</button> }
点击按钮2次以上控制台输出0、1、1,但渲染次数未增加。
原因:React的状态更新逻辑中,只要调用setState,无论新值和当前state是否相同,都会执行一次组件函数,但会跳过DOM更新(因为state无变化)。这就是为什么console.log(data)会多打印一次1——组件代码重新跑了一遍,但页面没重新渲染。React这么设计是为了保持逻辑一致性,避免开发者需要区分“值相同”和“值不同”的分支逻辑。
示例2:useEffect引发的额外日志
代码:
export const App = (props) => { const [data, setData] = useState(0) console.log(data) useEffect(() => { setData(1) }, [data]) return <></> }
同样出现额外日志输出。
原因:组件首次渲染时,data为0,执行console.log(0),随后useEffect触发并调用setData(1),state更新导致组件重新执行,打印1。此时useEffect的依赖数组[data]从0变为1,符合触发条件,所以再次执行useEffect并调用setData(1)。虽然新值和当前state相同,但React仍会让组件函数执行一次,因此多打印了一次1。不过因为state不再变化,后续useEffect不会再触发,不会形成无限循环。
示例3:直接在组件内调用setState导致无限循环
代码:
export const App = (props) => { const [data, setData] = useState(0) console.log(data) setData(1) return <button onClick={onClick}>button</button> }
出现无限循环。
原因:组件函数每次执行时,都会直接调用setData(1)。而调用setState必然会触发组件重新执行,由此形成闭环:组件执行→调用setData→组件重新执行→再次调用setData……循环往复无法停止。和示例1的核心区别是,示例1的setData由用户交互触发,而示例3是在组件渲染流程内直接调用,导致每次渲染都触发新的更新。
内容的提问来源于stack exchange,提问作者이명주
相关产品推荐
相关产品推荐

