React中useReducer重复dispatch问题排查求助
嘿,我来帮你搞定这两个头疼的问题:dispatch重复触发和切换艺术家时专辑列表被清空~
1. 切换艺术家时专辑被清空的核心原因
你在GET_ARTIST的Reducer逻辑里踩了个常见的坑:每次筛选专辑都是基于当前state.albums来过滤,而不是原始的完整专辑列表。
举个实际场景的例子:
- 第一次点击艺术家A,
state.albums被过滤成仅包含A的专辑 - 再点击艺术家B时,你是在已经过滤过的A的专辑列表里找B的专辑,自然找不到匹配项,所以
albums就变成空数组了
解决方法:保存原始专辑列表
你需要在AlbumState里额外维护一份原始的完整专辑列表,比如命名为allAlbums,每次筛选都基于这个原始列表来操作:
第一步:修改AlbumState的初始状态
const initialState = { albums: [], // 用于展示的筛选后的专辑 allAlbums: [], // 保存所有原始专辑,作为筛选的数据源 errorform: false, selectedartist: "", };
第二步:更新ADD_ALBUM的逻辑,同步维护原始列表
在添加新专辑时,同时更新allAlbums:
// AlbumState里的addAlbum方法 const addAlbum = (album) => { dispatch({ type: ADD_ALBUM, payload: album, }); }; // 对应的AlbumReducer的ADD_ALBUM case case ADD_ALBUM: return { ...state, albums: [action.payload, ...state.albums], allAlbums: [action.payload, ...state.allAlbums], // 同步更新原始专辑列表 };
第三步:修改GET_ARTIST的筛选逻辑,基于原始列表过滤
case GET_ARTIST: console.log(action.payload); return { ...state, selectedartist: action.payload, // 从原始的allAlbums里筛选,而不是当前的albums albums: state.allAlbums.filter( (album) => album.artist_creator === action.payload ), };
这样每次切换艺术家,都是从完整的专辑列表里筛选,就不会出现清空的问题了。
2. dispatch触发两次的问题
首先先清理你的AlbumReducer里的无效代码:GET_ARTIST case里有一个永远不会执行的多余return,删掉它:
// 删掉这行无效代码 return { ...state, selectedartist: action.payload };
然后,dispatch触发两次大概率是因为你开启了React严格模式(Strict Mode)。在开发环境下,Strict Mode会刻意重复调用一些函数(包括useReducer的dispatch、组件渲染等),用来帮你检测代码中的副作用问题,这是正常的开发环境行为,生产环境下不会出现这种情况。
如果想验证,可以暂时移除根组件的<React.StrictMode>标签,测试后你会发现dispatch只触发一次。不过更推荐保留Strict Mode,它能帮你提前发现潜在的代码问题,只要你的Reducer是纯函数(没有副作用,相同输入得到相同输出),即使dispatch被调用两次也不会影响最终状态。
另外,你可以给Artist组件加上React.memo来优化不必要的重渲染:
export default React.memo(Artist);
额外小建议
你把艺术家、专辑、歌曲的Context拆分独立,这个架构思路很棒!可以再优化一下:把getselectedArtist和getArtist这两个操作封装到一个自定义Hook里,让组件代码更简洁,也方便统一维护业务逻辑~
内容的提问来源于stack exchange,提问作者David Sabillon

