如何在派发action前检查store中实体是否存在并获取其快照?
你当然可以获取到store的当前快照,而且你遇到的多组件重复派发拉取用户action的问题,本身就是Redux项目里非常常见的优化场景,完全不需要靠每个组件自己写判断逻辑绕来绕去。
获取store当前快照的常用方法
- 如果你项目里导出了全局单例的store实例(一般在应用入口创建的那个),直接调用
store.getState()就能拿到任意时刻的完整只读状态快照,你可以在这个返回值里检查目标用户实体是否存在,再决定要不要派发拉取action。 - 如果你用了redux-thunk、redux-saga这类异步中间件,根本不需要手动引入全局store:中间件会自动把获取快照的
getState方法作为参数注入到你的异步逻辑里,函数内部随时调用就能拿到最新的store状态,不会有状态不同步的问题。
从根源解决重复请求的更优方案
不要把检查、拉取的逻辑散在每个Avatar组件里,最好把这套逻辑下沉到公共的异步action层,让所有用到Avatar的地方都复用同一套判断规则:
- 抽离一个通用的「按需拉取用户信息」的action creator,所有场景下要拉用户数据的时候统一调用这个方法,由action内部完成存在性检查,而不是每个组件各写各的判断:
// thunk形式的按需拉取逻辑示例 export const fetchUserIfNeeded = (userId) => (dispatch, getState) => { // 拿到当前store快照 const state = getState() const existingUser = state.user.entities[userId] const isLoading = state.user.loadingIds.includes(userId) // 已经存在用户数据、或者当前已经在加载这个用户的话,直接停止逻辑不发请求 if (existingUser || isLoading) return // 只有满足条件才真正发起请求 dispatch({ type: 'USER/FETCH_START', payload: userId }) return requestUserInfo(userId) .then(res => dispatch({ type: 'USER/FETCH_SUCCESS', payload: { userId, data: res } })) }
- Avatar组件本身改成纯渲染组件:只负责从store里根据传入的userId读取对应的用户头像、昵称做展示,本身不触发任何数据拉取动作。数据拉取的触发由上层业务、或者组件挂载时统一调用上面的公共方法即可。
实操时的注意细节
- 做判断的时候不要只检查用户实体是否存在,一定要同时检查对应id是否处于加载中状态,不然首次加载时多个Avatar同时挂载,都会检查到用户不存在,进而同时发好几个一模一样的请求,之前的重复问题还是会存在。
- 可以把实体存在性检查抽成通用工具函数,比如封装
isUserFetched(userId, state)这类方法,不管是Avatar、评论列表、用户资料卡这类其他要用到用户数据的组件,都可以复用同一套判断逻辑,不用重复写检查代码。
内容的提问来源于stack exchange,提问作者Nebex Elias
相关产品推荐
相关产品推荐

