React useReducer无法获取更新后状态的技术求助
问题:React中useReducer跨组件同步状态异常
我在React里仅使用useReducer,未用到Context API,现有三个组件:App、TogglePosts、ShowPosts,还有一个store。
当前流程:
- TogglePosts组件更新自身reducer的toggle状态,同时调用父组件App的回调函数;
- App将更新后的toggle值传递给ShowPosts组件;
- 我知道ShowPosts无法直接获取变更后的状态,因此用useEffect钩子同步,但点击Fetch Posts按钮时,ShowPosts始终拿到初始状态(toggle值为false)。
代码示例
App组件
import { useState } from "react"; import "./App.css"; import ShowPosts from "./components/ShowPosts"; import TogglePosts from "./components/TogglePosts"; function App() { const [appData, setAppData] = useState({ toggle: false }); function settingAppData(value) { value ? setAppData({ toggle: true }) : setAppData({ toggle: false }); } return ( <> <h3>Test Reducer</h3> <TogglePosts toggleFunc={settingAppData} /> <ShowPosts toggle={appData.toggle} /> </> ); } export default App;
TogglePosts组件
import { useReducer, useRef } from "react"; import { initialState, reducerFunc } from "../reducers/Store"; function TogglePosts({ toggleFunc }) { const inputToggle = useRef(); const [currState, dispatch] = useReducer(reducerFunc, initialState); function checkValue() { console.log("Checking Curr State value in toggle component :"); console.log(currState); } function handleToggleOncChange() { const toggleValue = inputToggle.current.checked; if (toggleValue) { const data = { type: "TOGGLE ON", payload: [], }; dispatch(data); console.log("Current state Value :"); console.log(currState); toggleFunc(true); } else { const data = { type: "TOGGLE OFF", payload: [], }; dispatch(data); console.log("Current state Value :"); console.log(currState); toggleFunc(false); } } return ( <> <input type="checkbox" className="btn-check" id="btn-check-2-outlined" ref={inputToggle} onChange={handleToggleOncChange} /> <label className={`btn ${currState.toggle ? "btn-primary" : "btn-warning"}`} htmlFor="btn-check-2-outlined" > {currState.toggle ? "Toggle is On" : "Toggle is Off"} </label> <br></br> <button onClick={checkValue} type="button" className="btn btn-primary"> Check Value </button> </> ); } export default TogglePosts;
ShowPosts组件
import { useEffect, useReducer } from "react"; import { initialState, reducerFunc } from "../reducers/Store"; import Post from "./Post"; function ShowPosts({ toggle }) { const [currState, dispatch] = useReducer(reducerFunc, initialState); useEffect(() => { if (toggle) { dispatch("TOGGLE ON"); } else { dispatch("TOGGLE OFF"); } }, [toggle]); function fetchPosts() { console.log("Checking Curr State value in Show component :"); console.log(currState); // fetch("https://dummyjson.com/posts") // .then((res) => res.json()) // .then((obj) => dispatch({ type: "DATA Fetch", payload: obj.posts })); } return ( <> <button type="button" style={{ margin: "10px" }} onClick={fetchPosts} className="btn btn-info" > Fetch Posts </button> <div className="container text-center"> <div className="row"> {currState.fetchData ? ( currState.fetchData.map((post) => ( <Post key={post.id} title={post.title} body={post.body} /> )) ) : ( <center> {"No Data to display"} </center> )} </div> </div> </> ); } export default ShowPosts;
Store
export const initialState = { toggle: false, fetchData: "", }; export const reducerFunc = (initialState, action) => { switch (action.type) { case "TOGGLE ON": console.log("In the on loop"); return { ...initialState, toggle: true }; case "TOGGLE OFF": console.log("In the off loop"); return { ...initialState, toggle: false }; case "DATA Fetch": return { ...initialState, fetchData: action.payload }; default: return initialState; } };
问题根源
- ShowPosts中dispatch参数格式错误:reducer期望接收包含
type属性的对象,但你在useEffect里直接传递了字符串"TOGGLE ON"/"TOGGLE OFF",导致reducer进入default分支,完全没更新状态。 - TogglePosts存在状态冗余:App已经维护了toggle状态,TogglePosts自己再用useReducer存一份,既多余又容易导致状态不一致。
- dispatch异步更新的闭包陷阱:TogglePosts里调用
dispatch后立刻打印currState,此时状态还没更新,因为dispatch是异步的,但这不是核心问题。
修复方案
1. 修正ShowPosts的dispatch参数格式
在useEffect里传递符合reducer要求的对象格式:
useEffect(() => { if (toggle) { dispatch({ type: "TOGGLE ON" }); } else { dispatch({ type: "TOGGLE OFF" }); } }, [toggle]);
2. 移除TogglePosts的冗余状态
直接使用App传递的toggle状态,简化组件逻辑:
// TogglePosts组件修改后 import { useRef } from "react"; function TogglePosts({ toggle, toggleFunc }) { const inputToggle = useRef(); function checkValue() { console.log("Checking Curr State value in toggle component :", toggle); } function handleToggleOncChange() { const toggleValue = inputToggle.current.checked; toggleFunc(toggleValue); } return ( <> <input type="checkbox" className="btn-check" id="btn-check-2-outlined" ref={inputToggle} onChange={handleToggleOncChange} checked={toggle} // 同步checkbox与App状态 /> <label className={`btn ${toggle ? "btn-primary" : "btn-warning"}`} htmlFor="btn-check-2-outlined" > {toggle ? "Toggle is On" : "Toggle is Off"} </label> <br /><br /> <button onClick={checkValue} type="button" className="btn btn-primary"> Check Value </button> </> ); } export default TogglePosts;
3. 简化App的状态更新逻辑
把appData拆成单独的toggle状态,让代码更直观:
// App组件修改后 import { useState } from "react"; import "./App.css"; import ShowPosts from "./components/ShowPosts"; import TogglePosts from "./components/TogglePosts"; function App() { const [toggle, setToggle] = useState(false); const settingAppData = (value) => { setToggle(value); }; return ( <> <h3>Test Reducer</h3> <TogglePosts toggle={toggle} toggleFunc={settingAppData} /> <ShowPosts toggle={toggle} /> </> ); } export default App;
内容的提问来源于stack exchange,提问作者RowLand
相关产品推荐
相关产品推荐

