React中子组件未正确更新父组件状态的问题排查
React子组件调用增量函数未正确更新count的问题解决
问题描述
将增量函数传递给一组子组件(Row),但count值始终未按预期更新。已知子组件useEffect写法存在问题,但无法理解该行为。另外未设置依赖数组,因为那样会导致count无限循环更新。
代码示例
import { useCallback, useEffect, useState } from "react"; import "./styles.css"; const list = ["One", "Two", "Three"]; export default function App() { const [count, setCount] = useState(0); const handleOnClick = useCallback(() => { setCount(count + 1); }, [count]); useEffect(() => { if (list.length === count) { alert("yaaay!"); } }, [count]); return ( <div className="App"> <h1>Count is: {count}</h1> {list.map((item) => ( <Row key={item} name={item} addOne={handleOnClick} /> ))} </div> ); } const Row = ({ addOne, name }) => { useEffect(() => { addOne(); // eslint-disable-next-line react-hooks/exhaustive-deps }, []); return <p>{name}</p>; };
实际输出
Count is: 1
One
Two
Three
预期输出
Count is: 3
One
Two
Three
问题根源
- 闭包捕获旧值:
handleOnClick通过useCallback包裹,依赖数组为[count]。但所有Row组件在首次挂载时,捕获的都是初始count=0对应的handleOnClick函数。三个Row的useEffect(空依赖,仅执行一次)调用addOne时,都是执行setCount(0+1),最终count仅更新为1。 - 空依赖限制副作用执行:Row组件的
useEffect依赖数组为空,仅在组件挂载时执行一次。后续即使count变化导致handleOnClick生成新函数,也不会重新触发副作用,无法调用更新后的函数。
修复方案
方案1:使用函数式更新(推荐)
修改handleOnClick,采用setCount的函数式更新形式,这样不需要依赖count,每次调用都会基于最新的count值计算:
const handleOnClick = useCallback(() => { setCount(prevCount => prevCount + 1); }, []); // 无需依赖count
此时三个Row组件调用addOne时,都会基于当前最新的count值递增,三次调用后count将正确更新为3。
方案2:控制Row组件副作用执行时机(不推荐)
若要保留原handleOnClick的依赖逻辑,可给Row的useEffect添加addOne到依赖数组,同时通过useRef标记是否为首次挂载,避免无限循环:
import { useRef } from "react"; const Row = ({ addOne, name }) => { const isMounted = useRef(false); useEffect(() => { if (!isMounted.current) { addOne(); isMounted.current = true; } }, [addOne]); return <p>{name}</p>; };
该方案需额外处理挂载状态,不如方案1简洁,仅在特殊场景下使用。
内容的提问来源于stack exchange,提问作者elhoucine
相关产品推荐
相关产品推荐

