如何解决更新state时React.useEffect与useCallback的循环依赖问题
解决方案
你遇到的循环问题核心是更新状态时直接引用了外层的state变量,导致必须将state加入依赖列表,状态更新后重新触发useEffect形成死循环。最优解是使用useState的函数式更新能力,无需引入复杂逻辑即可从根源解决问题:
当你给setState传入函数时,React会自动把当前最新的状态作为参数传入该函数,你不需要手动引用外层的state变量,自然不需要把state加入依赖列表。
场景1:直接在useEffect内更新状态
你的初始代码修复后如下,完全消除循环:
const [state, setState] = React.useState<IDataSource[]>([]) React.useEffect(() => { let dataSource: IDataSource[] = [] dataFetched.forEach((item, index) => { // 你的业务逻辑 }) // 函数式更新,无需引用外层state setState(prev => prev.concat(dataSource)) }, [dataFetched]) // 仅保留dataFetched依赖,无循环风险
场景2:需要封装updateData公共函数
如果需要把更新逻辑抽成公共函数,同样用函数式更新即可让useCallback的依赖数组为空,不会触发重复执行:
const [state, setState] = React.useState<IDataSource[]>([]) // 函数式更新不依赖外部state,依赖数组为空,updateData永远不会变化 const updateData = React.useCallback((arg: IDataSource[]) => { setState(prev => prev.concat(arg)) }, []) React.useEffect(() => { let dataSource: IDataSource[] = [] dataFetched.forEach((item, index) => { // 你的业务逻辑 }) updateData(dataSource) }, [dataFetched, updateData]) // updateData不会变化,不会触发effect重复执行
补充:useRef方案的适用场景
如果确实有特殊场景需要在回调中读取最新状态、又不想把状态加入依赖,才需要用到useRef做状态同步,你的当前场景不需要该方案,示例仅供参考:
const [state, setState] = React.useState<IDataSource[]>([]) const stateRef = React.useRef(state) // 状态每次更新同步到ref React.useEffect(() => { stateRef.current = state }, [state]) // 后续任意位置读取stateRef.current都能拿到最新状态,不需要把state加入依赖
内容的提问来源于stack exchange,提问作者Berg_Durden
相关产品推荐
相关产品推荐

