使用createStructuredSelector时Props更新组件不重渲染问题求助
问题分析与解决方案
你遇到的核心问题是:reselect的selector没有正确追踪到ownProps(也就是路由location)的变化,导致URL slug更新后,组件没有重新计算blogItem和blogItems,进而没有触发重渲染。
为什么会这样?
你当前在mapStateToProps中直接调用getBlogItem(slug)和getFollowingBlogItems(slug),相当于每次mapStateToProps执行时都创建了一个新的selector实例——reselect无法缓存这些临时创建的selector,也无法检测到slug参数的变化,自然不会重新计算结果。
正确的解决方案:让selector依赖ownProps
我们需要调整selector的定义,让它直接接收state和ownProps作为参数,通过reselect的依赖函数来获取slug,这样reselect就能自动追踪slug的变化,触发重新计算。
步骤1:重构你的selector文件(比如./selectors.js)
import { createSelector } from 'reselect'; // 定义基础的博客数据选择器 const selectBlogPosts = state => state.blogPosts; // 假设你的博客数据存在state.blogPosts下 // 定义从ownProps中提取当前slug的选择器 const selectCurrentSlug = (state, ownProps) => { // 提取URL末尾的slug,保留你原来的逻辑并添加容错 const matchResult = ownProps.location.pathname.match(/([^/]*)\/*$/); return matchResult ? matchResult[1] : ''; }; // 重构getBlogItem,依赖博客列表和当前slug export const getBlogItem = createSelector( [selectBlogPosts, selectCurrentSlug], (blogPosts, slug) => { // 找不到对应博客时返回空对象,和组件defaultProps对齐 return blogPosts.find(post => post.fields.slug === slug) || {}; } ); // 同理重构getFollowingBlogItems export const getFollowingBlogItems = createSelector( [selectBlogPosts, selectCurrentSlug], (blogPosts, slug) => { // 实现你的筛选逻辑:找到当前博客后取后续内容 const currentPostIndex = blogPosts.findIndex(post => post.fields.slug === slug); // 处理边界情况:如果找不到当前博客或已是最后一篇,返回空数组 if (currentPostIndex === -1 || currentPostIndex >= blogPosts.length - 1) { return []; } // 比如取当前博客之后的3条内容,可根据需求调整 return blogPosts.slice(currentPostIndex + 1, currentPostIndex + 4); } );
步骤2:简化mapStateToProps
现在不需要在mapStateToProps中手动传slug了,直接把重构后的selector传给createStructuredSelector——它会自动接收state和ownProps:
// 简化后的mapStateToProps const mapStateToProps = createStructuredSelector({ blogItem: getBlogItem, blogItems: getFollowingBlogItems });
步骤3:验证效果
当你点击Link切换URL slug时,ownProps.location会更新,selectCurrentSlug会检测到变化,触发getBlogItem和getFollowingBlogItems重新计算,组件会接收到新的blogItem和blogItems,从而自动重渲染。
额外优化建议
- 优化展示组件:如果
VisionBlogItem是纯组件,可以用React.memo包裹它,减少不必要的重渲染:export default React.memo(VisionBlogItem); - 清理冗余代码:你原来的
mapDispatchToProps只是返回dispatch,可以直接在connect中省略第二个参数,connect会默认把dispatch注入到props中。
内容的提问来源于stack exchange,提问作者Nappstir
相关产品推荐
相关产品推荐

