You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React.useCallback依赖state更新时未更新函数实现问题排查

问题原因分析

你遇到的confirmTodo始终读取初始状态的问题,核心有两个直接诱因:

  • 首先是updateTodo的实现存在闭包陷阱:你当前注释的setTodo({...todo, ...todoFragment})写法依赖了当前渲染闭包中的todo变量,同时你将todo加入了useCallback的依赖数组,这会导致每次todo更新时updateTodo都会生成新的函数实例。如果你的表单组件没有正确响应updateTodo的变化(比如挂载时绑定的事件回调仅捕获了初始版本的updateTodo),就会一直调用最初的updateTodo,而这个初始版本闭包里的todo永远是初始值,最终导致状态根本没有正常更新,confirmTodo自然读取不到最新的todo。
  • 其次是confirmTodo的依赖数组存在遗漏:你用到了来自AllTodosContext的addTodo,但没有将其加入依赖数组,虽然这不是你当前问题的直接原因,但会导致后续添加多条待办时出现异常。

另外还有两个隐藏问题需要修复:

  • AllTodosProvider中todos的初始状态为空,没有设置默认空数组,第一次调用addTodo时扩展undefined会报错。
  • NewTodoContext.Provider的value每次渲染都会生成新的对象,会导致所有消费该context的组件不必要重渲染。
修复方案

1. 修复NewTodoProvider逻辑

将updateTodo改为函数式状态更新,避免依赖todo,同时补全confirmTodo的依赖,用useMemo缓存context的value:

function NewTodoProvider({ children }){
   const [todo, setTodo] = React.useState(DEFAULT_EMPTY_TODO_STATE);
   
   const [ addTodo ] = React.useContext(AllTodosContext);
   
   const updateTodo = React.useCallback((todoFragment) => {
     // 改用函数式更新,不需要依赖外层todo
     setTodo(prevTodo => ({...prevTodo, ...todoFragment})) 
   }, []);
   
   // 补全addTodo依赖
   const confirmTodo = React.useCallback(() => { addTodo(todo) }, [todo, addTodo]);

   // 缓存context value避免不必要重渲染
   const contextValue = React.useMemo(() => ({
     todo,
     updateTodo,
     confirmTodo
   }), [todo, updateTodo, confirmTodo])

   return (
     <NewTodoContext.Provider value={contextValue}>
         { children }
     </NewTodoContext.Provider>
   )
}

2. 修复AllTodosProvider逻辑

给todos设置初始空数组,同时将addTodo改为函数式更新,避免依赖todos,减少不必要的函数实例更新:

function AllTodosProvider({ children }){
    // 加初始空数组
    const [todos, setTodos] = React.useState([]);
    // 改用函数式更新,不需要依赖外层todos
    const addTodo = React.useCallback((newTodo) => {
        setTodos(prevTodos => [...prevTodos, newTodo]);
    },[]);

   const contextValue = React.useMemo(() => ({
     todos,
     addTodo
   }), [todos, addTodo])

   return (
     <AllTodosContext.Provider value={contextValue}>
         { children }
     </AllTodosContext.Provider>
   )
}

内容的提问来源于stack exchange,提问作者alchemist95

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.27 18:15:03