React useEffect依赖警告、递归循环及资格判断异常问题求助
问题1:useEffect警告与无限循环
原因
- 依赖数组包含局部变量
showBadge,该变量每次渲染都会重新声明,导致useEffect频繁触发。 - 直接将
medicationState.EligibilityResponse加入依赖时,redux状态更新会生成新的对象引用,触发useEffect后又dispatch更新状态,形成循环。 - 原逻辑未关联当前
groupMedItem的唯一标识,无法判断是否已为当前药物获取过资格校验结果。
解决方案
- 移除依赖数组中的
showBadge,局部变量不应作为useEffect依赖。 - 通过
groupMedItem.getId()作为唯一标识,在useEffect中判断是否已为当前药物获取过有效响应(需同步调整redux reducer,将响应按id存储)。 - 使用
useSelector精准获取当前药物对应的资格响应,避免全局状态干扰。
问题2:showBadge始终为true
原因
- 所有
MedicationBadge组件共用同一个全局的EligibilityResponse,多个组件的请求响应会互相覆盖,导致显示错误结果。 - 赋值逻辑错误:仅当
isEligible为true时才更新showBadge,若isEligible为false,showBadge保持初始值false,但如果全局状态是其他药物的响应,就会错误显示true。 - 未处理响应未返回的情况,可能导致意外的真值判断。
解决方案
- 调整redux reducer,将资格校验响应按
groupMedItem的id存储(例如eligibilityResponses: { [id: string]: EligibilityResponse })。 - 修改
showBadge的赋值逻辑,直接根据当前药物的响应结果赋值,默认设为false。 - 在useEffect中仅当当前药物未获取过响应时才发起请求。
修改后的代码示例
import React, { useEffect } from 'react'; import { GroupMed } from '../../../../state/ducks/medications/models'; import { medicationsActions } from '../../../../state/ducks/medications'; import { useDispatch, useSelector } from 'react-redux'; import { ApplicationState } from '../../../../state/ducks'; import { ChaseJSON, ExMedJSON, FetchEligibilityRequest, PrescriptionJSON, } from '../../../../state/ducks/medications/types'; import { MedicationStatusProps } from './v2-recipes/medication-status'; export interface MedicationBadgeProps { index: number; groupMed: GroupMed; } const MedicationBadge: React.FC<MedicationStatusProps> = ({ index, groupMed }: MedicationBadgeProps) => { const dispatch = useDispatch(); const groupMedItem = groupMed.groupMedItems[0]; const itemId = groupMedItem.getId(); // 精准获取当前药物对应的资格响应 const eligibilityResponse = useSelector((state: ApplicationState) => state.medicationState.eligibilityResponses?.[itemId] ); // 直接赋值showBadge,默认false const showBadge = eligibilityResponse?.data?.isEligible ?? false; useEffect(() => { // 仅当当前药物未获取过有效响应时发起请求 if (!eligibilityResponse?.data) { const fetchEligibilityRequest: FetchEligibilityRequest = { rxcui: groupMedItem.getRxcui(), groupMedItemType: groupMedItem.item.groupMedItemType, groupMedItemDrug: (groupMedItem.item as ChaseJSON).drug || (groupMedItem.item as PrescriptionJSON).drug || (groupMedItem.item as ExMedJSON).externalMed.drug, medicationSearchResult: (groupMedItem.item as ChaseJSON).searchResult || (groupMedItem.item as ExMedJSON).externalMed?.healthProfileMedication?.searchResult, }; dispatch( medicationsActions.fetchEligibility(itemId, fetchEligibilityRequest), ); } }, [dispatch, itemId, groupMedItem]); return showBadge ? ( <ui-section flowDirection="horizontal" spacingTop="mini"> <ui-icon imgClass="eligible" spacingRight="mini" style={{ marginLeft: '0px' }}></ui-icon> </ui-section> ) : <></>; }; export default MedicationBadge;
补充:redux reducer调整示例
// medications reducer示例 const initialState = { // ...其他状态 eligibilityResponses: {} as Record<string, EligibilityResponse> }; export default function reducer(state = initialState, action: MedicationsAction) { switch (action.type) { case 'FETCH_ELIGIBILITY_SUCCESS': return { ...state, eligibilityResponses: { ...state.eligibilityResponses, [action.payload.id]: action.payload.response } }; // ...其他case default: return state; } }
内容的提问来源于stack exchange,提问作者Ajit Goel
相关产品推荐
相关产品推荐

