在TypeScript/React中从Provider访问Context时获取undefined值
问题:useContext结合useState实现全局状态时获取到undefined
问题描述
作为TypeScript和React Hooks新手,我在开发简易待办应用时尝试用useContext和useState实现全局状态管理。明明给useState设置了默认值,但在Provider中访问状态时却得到undefined。
原实现代码
Context与Provider组件
// TodoContext.tsx import { createContext, useState, ReactNode } from 'react'; interface Todo { id: number; text: string; completed: boolean; } interface TodoContextType { todos: Todo[]; addTodo: (text: string) => void; } // 创建Context,设置默认值占位 export const TodoContext = createContext<TodoContextType | undefined>(undefined); export const TodoProvider = ({ children }: { children: ReactNode }) => { const [todos, setTodos] = useState<Todo[]>([ { id: 1, text: '学习React Hooks', completed: false }, { id: 2, text: '学习TypeScript', completed: false } ]); const addTodo = (text: string) => { setTodos(prev => [...prev, { id: Date.now(), text, completed: false }]); }; return ( <TodoContext.Provider value={{ todos, addTodo }}> {children} </TodoContext.Provider> ); };
原App.tsx代码
// App.tsx import { useContext } from 'react'; import { TodoContext, TodoProvider } from './TodoContext'; function App() { // 在Provider的同级组件中直接调用useContext,导致获取到undefined const { todos } = useContext(TodoContext)!; return ( <TodoProvider> <div className="App"> <h1>待办列表</h1> <ul> {todos.map(todo => ( <li key={todo.id}>{todo.text}</li> ))} </ul> </div> </TodoProvider> ); } export default App;
问题原因
useContext只能在被Provider包裹的子组件中调用才能获取到正确的上下文值。原代码中App组件是TodoProvider的父级(直接渲染TodoProvider),此时调用useContext时,组件还未被TodoProvider包裹,无法获取上下文数据,返回的是创建Context时设置的默认值undefined。
解决方法
将访问Context状态的逻辑抽离到子组件中,确保该子组件被TodoProvider包裹,再在子组件内调用useContext。
修改后代码
新增TodoList子组件
// TodoList.tsx import { useContext } from 'react'; import { TodoContext } from './TodoContext'; export const TodoList = () => { const { todos } = useContext(TodoContext)!; return ( <ul> {todos.map(todo => ( <li key={todo.id}>{todo.text}</li> ))} </ul> ); };
修改后的App.tsx
// App.tsx import { TodoProvider } from './TodoContext'; import { TodoList } from './TodoList'; function App() { return ( <TodoProvider> <div className="App"> <h1>待办列表</h1> <TodoList /> </div> </TodoProvider> ); } export default App;
经@Erfan提示调整后,问题成功解决,现在可以正常获取到全局状态中的todos数据。
内容的提问来源于stack exchange,提问作者Jerryq27
相关产品推荐
相关产品推荐

