如何优化useEffect中多if-else的筛选逻辑,让代码更简洁?
宝可梦列表筛选逻辑重构优化
我在React的useEffect钩子中实现了一个筛选函数,依据三个下拉框的状态过滤显示的宝可梦内容。目前代码可正常运行,但结构复杂,新人难以理解,我希望重构得更简洁高效。我考虑过使用switch语句,也想过用pokedex.id < x && pokedex.id > y替代当前的setOffset和setLimit逻辑。
现有筛选代码
useEffect(() => { setFilteredPokedex( pokedex .filter((pokedex) => { return ( type === `all` || pokedex.types.map((pt) => pt.type.name).includes(type) ); }) .filter((pokedex) => { if (form === `default` && generation === `all`) { setOffset(0); setLimit(905); return pokedex; } else if (form === `regional - alola`) { setOffset(995); setLimit(30); return pokedex?.name?.includes(`alola`); } else if (form === `regional - galar`) { setOffset(1065); setLimit(25); return pokedex?.name?.includes(`galar`); } else if (form === `regional - hisui`) { setOffset(1133); setLimit(20); return ( pokedex?.name?.includes(`hisui`) || pokedex?.name?.includes(`origin`) ); } else if (form === `mega`) { setOffset(937); setLimit(70); return ( pokedex?.name?.includes(`-mega`) || pokedex?.name?.includes(`primal`) ); } else if (form === `gmax`) { setOffset(1099); setLimit(35); return pokedex?.name?.includes(`gmax`); } else if (generation === `gen1`) { setOffset(0); setLimit(151); return pokedex; } else if (generation === `gen2`) { setOffset(151); setLimit(100); return pokedex; } else if (generation === `gen3`) { setOffset(251); setLimit(135); return pokedex; } else if (generation === `gen4`) { setOffset(386); setLimit(107); return pokedex; } else if (generation === `gen5`) { setOffset(493); setLimit(156); return pokedex; } else if (generation === `gen6`) { setOffset(649); setLimit(72); return pokedex; } else if (generation === `gen7`) { setOffset(721); setLimit(88); return pokedex; } else if (generation === `gen8`) { setOffset(809); setLimit(96); return pokedex; } }), ); }, [ pokedex, form, generation, type ]);
补充的下拉框代码
<PokedexDropdown> <label htmlFor="form">Form</label> <select name="form" id="form" value={form} onChange={(e) => { setForm(e.target.value); setGeneration(`all`); setType(`all`); }} > <option value="default">Default</option> <option value="regional - alola">Regional - Alola</option> <option value="regional - galar">Regional - Galar</option> <option value="regional - hisui">Regional - Hisui</option> <option value="mega">Mega</option> <option value="gmax">Gmax</option> </select> </PokedexDropdown> <PokedexDropdown className={form === `default` ? `` : `hidden`}> <label htmlFor="generation">Generation</label> <select name="generation" id="generation" value={generation} onChange={(e) => { setGeneration(e.target.value); setForm(`default`); setType(`all`); }} > <option value="all">All</option> <option value="gen1">Generation I</option> <option value="gen2">Generation II</option> <option value="gen3">Generation III</option> <option value="gen4">Generation IV</option> <option value="gen5">Generation V</option> <option value="gen6">Generation VI</option> <option value="gen7">Generation VII</option> <option value="gen8">Generation VIII</option> </select> </PokedexDropdown> <PokedexDropdown> <label htmlFor="type">Type</label> <select name="type" id="type" value={type} onChange={(e) => { setType(e.target.value); }} > <option value="all">All</option> <option value="bug">Bug</option> <option value="dark">Dark</option> <option value="dragon">Dragon</option> <option value="electric">Electric</option> <option value="fairy">Fairy</option> <option value="fighting">Fighting</option> <option value="fire">Fire</option> <option value="flying">Flying</option> <option value="ghost">Ghost</option> <option value="grass">Grass</option> <option value="ground">Ground</option> <option value="ice">Ice</option> <option value="normal">Normal</option> <option value="poison">Poison</option> <option value="psychic">Psychic</option> <option value="rock">Rock</option> <option value="steel">Steel</option> <option value="water">Water</option> </select> </PokedexDropdown>
优化方案
1. 抽离配置常量,分离数据与逻辑
把形态、世代的筛选规则和参数抽成独立配置对象,避免大量嵌套的if-else,后续新增规则只需修改配置:
// 形态筛选配置:key对应下拉框value,包含offset、limit和筛选函数 const FORM_CONFIG = { 'default': { offset: 0, limit: 905, filter: () => true }, 'regional - alola': { offset: 995, limit: 30, filter: (poke) => poke.name.includes('alola') }, 'regional - galar': { offset: 1065, limit: 25, filter: (poke) => poke.name.includes('galar') }, 'regional - hisui': { offset: 1133, limit: 20, filter: (poke) => poke.name.includes('hisui') || poke.name.includes('origin') }, 'mega': { offset: 937, limit: 70, filter: (poke) => poke.name.includes('-mega') || poke.name.includes('primal') }, 'gmax': { offset: 1099, limit: 35, filter: (poke) => poke.name.includes('gmax') }, }; // 世代筛选配置:用宝可梦id范围替代offset/limit,更直观 const GENERATION_CONFIG = { 'all': { minId: 1, maxId: 905 }, 'gen1': { minId: 1, maxId: 151 }, 'gen2': { minId: 152, maxId: 251 }, 'gen3': { minId: 252, maxId: 386 }, 'gen4': { minId: 387, maxId: 493 }, 'gen5': { minId: 494, maxId: 649 }, 'gen6': { minId: 650, maxId: 721 }, 'gen7': { minId: 722, maxId: 809 }, 'gen8': { minId: 810, maxId: 905 }, };
2. 重构useEffect,拆分筛选逻辑
将类型、形态、世代的筛选拆分为独立函数,避免在filter回调中修改状态,减少不必要的组件渲染:
useEffect(() => { let currentOffset = 0; let currentLimit = 905; let formFilter = () => true; let generationFilter = () => true; // 处理形态筛选逻辑 if (form !== 'default') { const { offset, limit, filter } = FORM_CONFIG[form]; currentOffset = offset; currentLimit = limit; formFilter = filter; } else { // 处理世代筛选逻辑(默认形态下生效) const { minId, maxId } = GENERATION_CONFIG[generation]; currentOffset = minId - 1; // 若offset为数组索引,对应id起始位置的索引 currentLimit = maxId - minId + 1; generationFilter = (poke) => poke.id >= minId && poke.id <= maxId; } // 处理类型筛选逻辑 const typeFilter = (poke) => { return type === 'all' || poke.types.some(t => t.type.name === type); }; // 合并所有筛选条件,生成最终列表 const filteredList = pokedex.filter(poke => typeFilter(poke) && formFilter(poke) && generationFilter(poke) ); // 统一设置状态,避免多次触发渲染 setOffset(currentOffset); setLimit(currentLimit); setFilteredPokedex(filteredList); }, [pokedex, form, generation, type]);
3. 下拉框代码优化(可选)
把下拉框选项也用配置生成,减少重复代码,后续新增选项只需修改配置:
// 形态选项配置 const FORM_OPTIONS = [ { value: 'default', label: 'Default' }, { value: 'regional - alola', label: 'Regional - Alola' }, { value: 'regional - galar', label: 'Regional - Galar' }, { value: 'regional - hisui', label: 'Regional - Hisui' }, { value: 'mega', label: 'Mega' }, { value: 'gmax', label: 'Gmax' }, ]; // 世代选项配置 const GENERATION_OPTIONS = [ { value: 'all', label: 'All' }, { value: 'gen1', label: 'Generation I' }, { value: 'gen2', label: 'Generation II' }, { value: 'gen3', label: 'Generation III' }, { value: 'gen4', label: 'Generation IV' }, { value: 'gen5', label: 'Generation V' }, { value: 'gen6', label: 'Generation VI' }, { value: 'gen7', label: 'Generation VII' }, { value: 'gen8', label: 'Generation VIII' }, ];
渲染下拉框时直接映射配置:
<select name="form" id="form" value={form} onChange={(e) => { setForm(e.target.value); setGeneration('all'); setType('all'); }} > {FORM_OPTIONS.map(opt => ( <option key={opt.value} value={opt.value}>{opt.label}</option> ))} </select>
优化亮点
- 可读性提升:配置与逻辑分离,新人快速理解规则,无需通读冗长的if-else
- 可维护性提升:新增/修改筛选规则只需调整配置对象,无需改动核心筛选逻辑
- 性能优化:避免在filter回调中调用setState,减少不必要的组件重渲染
- 逻辑直观:世代筛选用宝可梦官方id范围替代offset,更符合认知习惯
内容的提问来源于stack exchange,提问作者Tibo
相关产品推荐
相关产品推荐

