React Router跨路由下useSelector不响应Redux状态变更求助
Redux + React Router 状态更新不渲染问题排查与修复
问题描述
我是Redux新手,正在做测试项目理解Redux和React Router的结合用法。目标是在edi1路由点击提交后,用用户输入更新Redux状态,然后在edi2路由通过useSelector显示更新后的状态。目前edi1路由里,useSelector和Redux DevTools Profiler都能看到状态正常更新,但edi2路由只渲染store的初始状态,完全不响应状态变更——就算刷新edi2标签页,状态还是初始值。
我查了React Router和Redux Toolkit的文档,React Router v5提到如果要「将路由数据和store同步并从store访问」,推荐用“深度Redux集成”,但我用的是React Router 6.4.1,不确定是否适用。
代码文件
store.js
import { configureStore } from '@reduxjs/toolkit' import ediReducer from './ediSlice' export const store = configureStore({ reducer: { edi: ediReducer, }, })
ediSlice.js
import {createSlice} from '@reduxjs/toolkit'; const initialState = { id:0, content: ["Hello World"], } export const ediSlice = createSlice({ name: 'edi', initialState, reducers: { addContent: (state, action) => { state.content.push(action.payload); state.id += 1 console.log(state.id) }, } }) export const {addContent} = ediSlice.actions; export default ediSlice.reducer;
SendEdi.js
import { Editor } from '@tinymce/tinymce-react'; import {useRef, useState} from "react"; import {useSelector, useDispatch} from "react-redux"; import {addContent} from "../components/ediSlice.js"; export default function SendEdi() { const ediContent = useSelector((state) => state.edi.content); const dispatch = useDispatch() const editorRef = useRef(); const [entryArray, setEntryArray] = useState(); const log = () => { if (editorRef.current) { setEntryArray(editorRef.current.getContent()); dispatch(addContent(entryArray)); console.log("Editor Conent:", {ediContent}) }} let entryEdi = <Editor onInit={(evt, editor) => editorRef.current = editor} apiKey='your-api-key' disabled = {false} inline = {false} init={{ selector: "#entryEdi", height: 500, menubar: false, placeholder: "Whats on your mind?", plugins: [ 'advlist', 'autolink', 'lists', 'link', 'image', 'charmap', 'preview', 'anchor', 'searchreplace', 'visualblocks', 'code', 'fullscreen', 'insertdatetime', 'media', 'table', 'code', 'help', 'wordcount' ], toolbar: 'undo redo | blocks | ' + 'bold italic forecolor | alignleft aligncenter ' + 'alignright alignjustify | bullist numlist outdent indent | ' + 'removeformat | help', content_style: 'body { font-family:Helvetica,Arial,sans-serif; font-size:14px }' }} /> return ( <div> {ediContent} {entryEdi} <button onClick={log}>Submit</button> </div> ) }
RecEdi.js
import {useSelector} from "react-redux"; export default function RecEdi() { const ediContent = useSelector((state) => state.edi.content); return ( <div> {ediContent} </div> ) }
App.js
import { BrowserRouter as Router, Routes, Route } from "react-router-dom"; import Edi1 from "./pages/edi1"; import Edi2 from "./pages/edi2"; function App() { return ( <div className="App"> <Router> <Routes> <Route path="/Edi1" element={<Edi1 />} /> <Route path="/Edi2" element={<Edi2 />} /> </Routes> </Router> </div> ); } export default App;
edi1.js
import SendEdi from "../components/SendEdi.js"; export default function Edi1() { return ( <div> <SendEdi /> <h1>edi1</h1> </div> ); }
edi2.js
import RecEdi from "../components/RecEdi"; export default function Edi2() { return ( <div> <RecEdi /> <h1>edi2</h1> </div> ); }
index.js
import React from "react"; import ReactDOM from "react-dom/client"; import App from "./App"; import { store } from "./components/store.js"; import { Provider } from "react-redux"; const root = ReactDOM.createRoot(document.getElementById("root")); root.render( <React.StrictMode> <Provider store={store}> <App /> </Provider> </React.StrictMode> );
问题根源
- dispatch时机错误:
setEntryArray是异步更新React本地状态的操作,调用dispatch(addContent(entryArray))时,entryArray还未更新为编辑器的最新内容,第一次点击时甚至是undefined,导致store中添加了无效值。 - 无需深度Redux集成:React Router 6与Redux结合无需额外的深度集成配置,只要所有组件都在
Provider包裹范围内即可,你的组件结构已经满足这个要求。
修复方案
修改SendEdi.js中的log函数,直接获取编辑器内容并dispatch,跳过本地state中转:
export default function SendEdi() { const ediContent = useSelector((state) => state.edi.content); const dispatch = useDispatch() const editorRef = useRef(); // 移除不必要的本地state // const [entryArray, setEntryArray] = useState(); const log = () => { if (editorRef.current) { // 直接获取编辑器最新内容 const latestContent = editorRef.current.getContent(); dispatch(addContent(latestContent)); console.log("Editor Content:", latestContent); }} // 其余代码保持不变... }
修改后,点击提交按钮时会直接将编辑器的最新内容发送到store,edi1和edi2路由的useSelector都会正确响应状态变更,edi2页面就能显示更新后的内容了。
内容的提问来源于stack exchange,提问作者CreativeDesign
相关产品推荐
相关产品推荐

