React useEffect遍历JSON切换状态实现工作地点筛选问题排查
代码存在的问题
- 异步逻辑处理完全错误:
fetchLocationData是async声明的异步函数,直接调用会返回Promise对象,你把这个Promise赋值给condition后立刻调用filter方法,此时既没有拿到接口返回的真实职位数组,Promise对象本身也没有filter方法,运行时会直接报错。 Array.filter使用错误:filter是不会修改原数组的纯函数,执行后会返回筛选后的新数组,你在switch分支中调用condition.filter()后没有接收返回值,筛选操作没有任何实际效果。- URL参数设计逻辑错误:你试图把筛选后的完整职位结果塞进URL参数,这是完全不合理的设计——URL参数仅需要存储当前选中的筛选条件值即可,塞全量结果会导致URL过长、解析失败;另外代码里写的
${condition.con}是无效取值,con只是filter回调里的临时形参,外部根本无法访问,且筛选后的condition是数组类型,不存在con属性,最终只会得到undefined。 - useEffect依赖项缺失:当前effect依赖数组仅写了
jobCondition,但内部用到了jobFilter、locationFilter、datePosted、history等多个外部变量,这些变量变化时不会触发effect重新执行,会出现闭包旧值、参数不同步的问题。 - 空值处理错误:给
URLSearchParams直接传入null作为值时,会被序列化成字符串"null",不是预期的空值效果,会导致后端/前端解析参数出错。 - 默认分支逻辑冲突:default分支把
condition设为null后,后续构造参数时硬编码把since、conditions设为null,没有读取当前已选中的datePosted值,会导致切换到“全部地点”选项时,已选的发布时间筛选被意外清空。
修正后的实现代码
import { useEffect, useState } from 'react'; import { useHistory } from 'react-router-dom'; // 接口请求函数建议抽离到组件外或单独的api文件 const fetchLocationData = async () => { const res = await getJobs(); if (!res.ok) throw new Error('职位数据拉取失败'); return res.json(); }; // 组件内部 const [allJobs, setAllJobs] = useState([]); // 存储全量职位数据 const [filteredJobs, setFilteredJobs] = useState([]); // 存储筛选后要渲染的职位 const history = useHistory(); // effect1:组件挂载时拉取一次全量职位数据 useEffect(() => { const loadAllJobs = async () => { try { const jobs = await fetchLocationData(); setAllJobs(jobs); setFilteredJobs(jobs); } catch (err) { console.error('职位加载失败:', err); // 可在此处加页面错误提示 } }; loadAllJobs(); }, []); // effect2:工作地点筛选条件变化时,过滤职位数据 useEffect(() => { let result = allJobs; switch (jobCondition) { case 'On-site': result = allJobs.filter(job => job.jobLocation === 'in_person'); break; case 'Remote': result = allJobs.filter(job => job.jobLocation === 'remote'); break; case 'Hybrid': result = allJobs.filter(job => job.jobLocation === 'hybrid'); break; default: break; } setFilteredJobs(result); }, [jobCondition, allJobs]); // effect3:所有筛选条件变化时,同步参数到URL useEffect(() => { const params = new URLSearchParams(); // 仅当参数有有效值时才追加到URL,避免出现"null"字符串 if (jobFilter) params.set('jobs', jobFilter); if (locationFilter) params.set('location', locationFilter); if (datePosted) params.set('since', datePosted); if (jobCondition && jobCondition !== 'All') params.set('workType', jobCondition); history.push({ pathname: '/', search: params.toString() }); }, [jobFilter, locationFilter, datePosted, jobCondition, history]);
关键修正说明
- 拆分逻辑关注点:把「拉取全量数据」「筛选数据渲染」「同步筛选条件到URL」三个独立逻辑拆成三个独立的useEffect,避免逻辑混杂导致的执行顺序错误。
- 修正异步处理方式:异步请求在effect内部的async函数中执行,拿到真实数组数据后再做后续过滤操作,不会直接操作Promise对象。
- 修正数组filter用法:接收filter返回的新数组,赋值后更新到渲染state中,筛选操作能实际生效。
- 修正URL参数逻辑:URL仅存储筛选条件的取值,不存完整筛选结果,避免URL异常;参数有值才追加到查询串,不会出现值为
"null"的无效参数。 - 补全useEffect依赖:所有effect内部用到的响应式变量全部加入依赖数组,避免闭包旧值问题。
- 修正默认分支逻辑:不选特定工作地点时默认展示全量职位,切换地点筛选时不会清空其他已选的筛选条件。
如果你的筛选是后端接口支持的服务端筛选,可以把筛选参数直接传给
getJobs接口,不需要前端拉全量数据再过滤,逻辑会更简单。
内容的提问来源于stack exchange,提问作者Yuradzi
相关产品推荐
相关产品推荐

