如何用reduce简化React中嵌套forEach的分包商筛选代码?
简化React中分包商筛选条件响应数据的处理逻辑
我需要实现的功能是:从已提交的分包商列表中,提取每个分包商对应**指定筛选条件(criteriaId)**的响应数据。分包商对象包含selectionCriteria数组,每个数组元素包含files、id、request(筛选条件配置)、response(响应值)等字段。目前用嵌套forEach实现,但代码逻辑冗余,想改用reduce或其他更简洁的方式优化这段React代码。
原代码如下:
const { subcontractors } = useLoaderData<typeof loader>(); const { t } = useTranslation(); const submittedSubcontractors = subcontractors.filter( (s) => s.status === 'submitted' ); const subcontractorsResponsesToSelectionCriteria: Array<ISubcontractor> = []; let providedAnswersResponded: boolean | null = null; let providedAnswersFiles: Array<IFile> | [] = []; let providedAnswersRequiresFiles: boolean | null = null; submittedSubcontractors.forEach((u) => { u.selectionCriteria.forEach((c) => { if (c.request.id === criteriaId) { if (c.response && 'answer' in c.response) { if (typeof c.response.answer === 'boolean') { providedAnswersResponded = c.response.answer; } else { providedAnswersResponded = null; } } else { providedAnswersResponded = null; } providedAnswersFiles = c.files; providedAnswersRequiresFiles = c.request.are_files_required; subcontractorsResponsesToSelectionCriteria.push(u as ISubcontractor); } }); });
优化方案1:用reduce实现函数式处理
原代码的核心问题是依赖零散全局变量存储临时值,嵌套forEach的逻辑可读性差。用reduce可以把筛选、匹配、数据提取整合为链式调用,同时消除全局变量:
const { subcontractors } = useLoaderData<typeof loader>(); const { t } = useTranslation(); // 整合所有逻辑:过滤已提交分包商 + 匹配指定筛选条件 + 提取响应数据 const { matchedSubcontractors, latestResponse: { responded, files, requiresFiles } } = subcontractors .filter(s => s.status === 'submitted') .reduce((acc, subcontractor) => { // 找到当前分包商中匹配criteriaId的筛选条件项 const matchedCriteria = subcontractor.selectionCriteria.find( c => c.request.id === criteriaId ); if (matchedCriteria) { // 提取响应状态(和原逻辑保持一致:仅当answer是布尔值时赋值,否则为null) const responded = matchedCriteria.response && 'answer' in matchedCriteria.response && typeof matchedCriteria.response.answer === 'boolean' ? matchedCriteria.response.answer : null; // 更新累加器:添加匹配的分包商,同时覆盖为最新的响应数据 return { matchedSubcontractors: [...acc.matchedSubcontractors, subcontractor], latestResponse: { responded, files: matchedCriteria.files, requiresFiles: matchedCriteria.request.are_files_required } }; } // 无匹配项时返回原累加器 return acc; }, { matchedSubcontractors: [] as ISubcontractor[], latestResponse: { responded: null as boolean | null, files: [] as IFile[], requiresFiles: null as boolean | null } });
优化点说明
- 消除全局变量:用
reduce的累加器统一存储结果,避免零散临时变量 - 逻辑分层清晰:链式调用把“筛选已提交分包商”“匹配指定条件”“提取响应数据”拆分为独立步骤
- 修复潜在冗余:原代码若一个分包商有多个匹配
criteriaId的项,会重复添加分包商;优化后用find只取第一个匹配项,避免重复(若业务确实需要重复添加,可将find改为filter遍历) - 类型安全:保留TypeScript类型定义,避免类型丢失
优化方案2:拆分逻辑为独立函数(高可维护性)
如果追求直观性和可复用性,可以把数据提取逻辑拆为独立函数,保留forEach的简洁性:
const { subcontractors } = useLoaderData<typeof loader>(); const { t } = useTranslation(); // 提取单个筛选条件的响应数据(可复用) const extractCriteriaResponse = (criteria: typeof subcontractors[0]['selectionCriteria'][0]) => { const responded = criteria.response && 'answer' in criteria.response && typeof criteria.response.answer === 'boolean' ? criteria.response.answer : null; return { responded, files: criteria.files, requiresFiles: criteria.request.are_files_required }; }; // 主逻辑 const submittedSubcontractors = subcontractors.filter(s => s.status === 'submitted'); const matchedSubcontractors: ISubcontractor[] = []; let latestResponse = { responded: null as boolean | null, files: [] as IFile[], requiresFiles: null as boolean | null }; submittedSubcontractors.forEach(sub => { const matchedCriteria = sub.selectionCriteria.find(c => c.request.id === criteriaId); if (matchedCriteria) { matchedSubcontractors.push(sub); latestResponse = extractCriteriaResponse(matchedCriteria); } });
这种方式把复杂的条件判断封装为独立函数,主逻辑更易读,同时保留了原代码的执行逻辑。
内容的提问来源于stack exchange,提问作者MiRAY
相关产品推荐
相关产品推荐

