React Redux与Context API:如何通过Context传递属性并保持其响应式连接?
问题分析与解决方案
嘿,这个问题我碰到过好多次了!咱们先拆解下为啥会出现“Redux状态更新了但组件不渲染”的情况,再一步步解决。
问题根源
你在AppProvider里用useStore().getState()获取posts,这个方法是一次性读取当前状态快照,不会订阅Redux Store的变化。也就是说,当你dispatchdeletePost动作后,Redux里的posts确实更新了,但AppProvider完全不知道这件事——它不会重新渲染,自然也不会更新AppContext.Provider的value。下游用useApp()拿到的还是旧的posts数组,组件当然不会重新渲染啦。
解决方案:用useSelector订阅状态变化
React-Redux提供的useSelector钩子会自动订阅你指定的状态片段,当这个片段变化时,使用该钩子的组件(这里就是AppProvider)会重新渲染,进而更新Context的value。咱们来修改代码:
修改context.js
import { useDispatch, useSelector } from "react-redux"; // 替换useStore为useSelector import { useContext, createContext } from "react"; import { deletePost } from "./redux/actions/posts"; export const AppContext = createContext(); export const useApp = () => { return useContext(AppContext); }; export const AppProvider = ({ children }) => { const dispatch = useDispatch(); // 用useSelector订阅posts的变化,代替一次性getState const posts = useSelector(state => state.posts.items); // 把deletePost和dispatch绑定好,组件里直接调用不用再单独拿dispatch const handleDeletePost = (id) => { dispatch(deletePost(id)); }; const value = { posts, handleDeletePost, // 用绑定好的方法代替原deletePost和dispatch // 如果还有其他需要dispatch的动作,也可以在这里统一封装 }; return <AppContext.Provider value={value}>{children}</AppContext.Provider>; };
修改Post.js(简化调用逻辑)
import { useApp } from "../context"; const Post = ({ title, content, id }) => { const { handleDeletePost } = useApp(); const onDeleteClick = () => { console.log("delete it", id); handleDeletePost(id); // 直接调用封装好的方法 }; return ( <article> <h1>{title}</h1> <p>{content}</p> <div className="toolbar"> <button onClick={onDeleteClick}>Delete</button> </div> </article> ); }; export default Post;
可选:简化Home.js
原来的connect()(Home)是空连接,完全可以去掉——现在Home是通过useApp()获取posts的函数组件,不需要再用connect包裹:
import Post from "../components/Post"; import { useApp } from "../context"; const Home = () => { const { posts } = useApp(); return ( <section> {posts.map((p) => ( <Post key={p.id} {...p} /> ))} </section> ); }; export default Home; // 去掉冗余的connect()
为什么这样能解决问题?
useSelector会订阅state.posts.items的变化,当你删除文章后,Redux里的posts.items更新,useSelector会触发AppProvider重新渲染。AppProvider重新渲染时,会生成包含最新posts的新value对象,AppContext.Provider会把新值传递给所有消费它的组件。Home和Post组件通过useApp()拿到最新的posts和方法,自然会重新渲染,界面也就跟着更新了。
内容的提问来源于stack exchange,提问作者Sisir
相关产品推荐
相关产品推荐

