React根组件用useDispatch定义回调遇Redux上下文错误求助
问题解决:Redux Context未找到错误
错误根源
你直接在App组件中调用useDispatch和useSelector,但<Provider>是在App的return语句里渲染的——App组件本身并不在Provider的上下文包裹范围内,导致Redux hooks无法获取到store,从而抛出"Could not find react-redux context value"错误。
解决方案
有两种可行的修复方式,根据你的需求选择:
方案1:将Redux Provider移到App组件外部
把<Provider>的包裹逻辑放到入口文件(如index.tsx)中,让App组件整体处于Redux上下文里,这样就能在App内部正常使用Redux hooks。
修改入口文件(index.tsx):
import React from 'react'; import ReactDOM from 'react-dom/client'; import App from './App'; import { Provider } from 'react-redux'; import { createStore } from "redux"; import rootReducer from "./redux"; import { composeWithDevTools } from "redux-devtools-extension"; // 初始化store(后续建议改用@reduxjs/toolkit的configureStore,createStore已废弃) const store = createStore(rootReducer, composeWithDevTools()); const root = ReactDOM.createRoot(document.getElementById('root') as HTMLElement); root.render( <Provider store={store}> <App /> </Provider> );
修改App.tsx:
移除App内部的<Provider>渲染,同时修正handleClick的依赖数组(必须包含selectedValue和inputValue,否则回调不会响应状态变化):
import React, { useCallback } from 'react'; import './App.css'; import { Card } from './components/organism/Card'; import { useState } from "react"; import { Context } from './context/Context' import { imgData } from "./context/Context"; import { useDispatch, useSelector } from "react-redux"; import StudentExercise from "./components/organism/studentExercise/studentExercise"; import { setBirthYear, setCourse, setName, setSurname, setTutor } from "./redux/actions"; export type RootState = ReturnType<typeof store.getState> function App() { // 本地状态 const [value, setValue] = useState('My context value'); const [imageData, setImageData] = useState(imgData); // 现在可正常调用Redux hooks const dispatch = useDispatch(); const selectedValue: string|undefined = useSelector((state: RootState) => state.selectedOption); const inputValue: string|null = useSelector((state: RootState) => state.inputTextValue); // 修正依赖数组,加入状态变量确保回调更新 const handleClick = useCallback(()=> { switch(selectedValue) { case "name": console.log("Selected value --> ",selectedValue); console.log(inputValue); return dispatch(setName(inputValue)); case "surname": return dispatch(setSurname(inputValue)); case "birthYear": return dispatch(setBirthYear(inputValue)); case "course": return dispatch(setCourse(inputValue)); case "tutor": return dispatch(setTutor(inputValue)); default: return selectedValue; } }, [dispatch, selectedValue, inputValue]); return ( <div className="App"> <Context.Provider value={{ value, setValue }}> <Card /> </Context.Provider> <StudentExercise clickHandler={handleClick} title={"changing values!"} /> </div> ); } export default App;
方案2:拆分组件,将Redux相关逻辑移到Provider内部的子组件
如果不想修改入口文件,可以创建一个新的子组件(如AppContent),把需要使用Redux hooks的逻辑放到这个子组件里,让它被<Provider>包裹:
// App.tsx import React, { useState, useCallback } from 'react'; import './App.css'; import { Card } from './components/organism/Card'; import { Context } from './context/Context' import { imgData } from "./context/Context"; import { Provider, useDispatch, useSelector } from "react-redux"; import StudentExercise from "./components/organism/studentExercise/studentExercise"; import { createStore } from "redux"; import rootReducer from "./redux"; import { composeWithDevTools } from "redux-devtools-extension"; import { setBirthYear, setCourse, setName, setSurname, setTutor } from "./redux/actions"; export type RootState = ReturnType<typeof store.getState> const store = createStore(rootReducer, composeWithDevTools()); // 子组件:处理Redux相关逻辑,处于Provider上下文内 function AppContent({ value, setValue }: { value: string; setValue: React.Dispatch<React.SetStateAction<string>> }) { const dispatch = useDispatch(); const selectedValue: string|undefined = useSelector((state: RootState) => state.selectedOption); const inputValue: string|null = useSelector((state: RootState) => state.inputTextValue); const handleClick = useCallback(()=> { switch(selectedValue) { case "name": console.log("Selected value --> ",selectedValue); console.log(inputValue); return dispatch(setName(inputValue)); case "surname": return dispatch(setSurname(inputValue)); case "birthYear": return dispatch(setBirthYear(inputValue)); case "course": return dispatch(setCourse(inputValue)); case "tutor": return dispatch(setTutor(inputValue)); default: return selectedValue; } }, [dispatch, selectedValue, inputValue]); return ( <> <Context.Provider value={{ value, setValue }}> <Card /> </Context.Provider> <StudentExercise clickHandler={handleClick} title={"changing values!"} /> </> ) } function App() { const [value, setValue] = useState('My context value'); const [imageData, setImageData] = useState(imgData); return ( <div className="App"> <Provider store={store}> <AppContent value={value} setValue={setValue} /> </Provider> </div> ); } export default App;
额外提示
createStore已被Redux官方废弃,建议迁移到Redux Toolkit的configureStore,它内置了最佳实践,配置更简洁。useCallback的依赖数组必须包含所有在回调中使用的外部变量,否则会导致回调捕获旧值,无法响应状态更新。
内容的提问来源于stack exchange,提问作者alessandro_marti01
相关产品推荐
相关产品推荐

