React中如何在useMemo初始函数块外修改返回值实现名称搜索
问题根因
你的useEffect赋值逻辑不生效是React的基本渲染规则导致的:
dbzCharacters本质是组件每次渲染时,useMemo返回的局部派生变量。你在effect里对这个局部变量重新赋值,仅在effect执行的当前上下文生效,下一次组件重渲染时,这个变量会被useMemo重新计算返回的筛选结果直接覆盖,修改根本留不住。- 这种直接改渲染派生值的写法本身不符合React单向数据流的要求,也不会触发组件重渲染,视图自然拿不到过滤后的结果。
解决方案
完全不用把搜索逻辑塞进原有useMemo堆判断分支,用分层派生的方式拆逻辑就行,原有性别/种族筛选的代码一点不用动,单独加一层useMemo处理名称搜索,两层逻辑完全独立,没有多余分支:
// 原有性别、种族筛选逻辑保持不动,仅更改变量名做区分 const filteredByTrait = useMemo<CharacterObj[]>(() => { if (filterGenderValue && filterRaceValue) { return characters.filter( (char: CharacterObj) => char.race === filterRaceValue && char.gender === filterGenderValue ); } else if (filterGenderValue && !filterRaceValue) { return characters.filter( (char: CharacterObj) => char.gender === filterGenderValue ); } else if (!filterGenderValue && filterRaceValue) { return characters.filter( (char: CharacterObj) => char.race === filterRaceValue ); } else { return characters; } }, [filterGenderValue, filterRaceValue, characters]); // 单独处理搜索逻辑,基于上一步的筛选结果做二次过滤 const dbzCharacters = useMemo<CharacterObj[]>(() => { // 搜索词长度不满足要求时直接返回上一步结果 if (search.length <= 1) return filteredByTrait; const keyword = search.toLowerCase(); return filteredByTrait.filter(({ name }) => name?.toLowerCase().includes(keyword) ); }, [filteredByTrait, search]);
这个写法的优势:
- 两层筛选逻辑完全解耦,后续改任意一层的筛选规则都不会影响另一层,不会出现多层if/else嵌套难维护的问题
- 所有派生值都走
useMemo做缓存,性能和把所有逻辑塞到同一个useMemo里没有差异 - 不需要额外声明state存储筛选结果,从根源上避免状态不同步的bug
补充个开发规范:不要用
useEffect处理渲染派生数据。所有能基于现有state、props直接计算出来的结果,都应该在渲染阶段通过useMemo派生,useEffect只用来处理和外部系统交互的副作用,比如接口请求、DOM操作、事件绑定这类逻辑。
内容的提问来源于stack exchange,提问作者Ben_Sven_Ten
相关产品推荐
相关产品推荐

