如何重构Hook调用避免无效Hook错误并正确传递状态
问题解决:React Hook调用错误及代码重构
问题还原
报错信息:Error: Invalid hook call. Hooks can only be called inside of the body of a function component.
需求:重构代码,确保将每个assessmentData推入listItems时,能传递对应正确的isGood和isSubGood状态,问题出在listItems.push的代码逻辑里。
错误根源
- 闭包陷阱:在
useEffect循环里调用setIsGood/setIsSubGood后立即获取状态值,由于闭包特性,拿到的永远是组件初始化时的false,并非刚更新的状态。 - 状态滥用:
isGood/isSubGood是每个assessmentData的临时计算值,不需要放到组件全局状态中,全局状态应只存储跨渲染周期共享或控制UI显示的值。 - 变量追踪失效:
listItems是普通变量,React无法追踪其变化,组件重新渲染时会被重置,加上useEffect空依赖仅执行一次,导致渲染内容异常。 - 拼写错误:代码中
setIsGoog(true)是笔误,应为setIsGood(true)。
重构后的代码
export default function AssessmentsGraphData(props) { const [createModal, setCreateModal] = React.useState(false); const [error, setError] = React.useState(false); const { data: graphData, isUserAllowedEdit, userId, handleUpdateSuccess } = props; // 用useMemo缓存处理后的listItems,避免重复计算 const listItems = React.useMemo(() => { if (!graphData) return []; return graphData.map((assessmentData) => { // 实时计算当前assessment对应的isGood和isSubGood let isGood = false; let isSubGood = false; if (assessmentData.assessmentType === 'HERE') { isGood = true; } if (['THAT', 'THIS', 'OTHER'].includes(assessmentData.assessmentType)) { isGood = true; isSubGood = true; } return Assessment.individualAssessment( assessmentData, userId, isGood, isSubGood, isUserAllowedEdit, handleUpdateSuccess, ); }); }, [graphData, userId, isUserAllowedEdit, handleUpdateSuccess]); // 计算全局isGood,用于控制底部Card显示 const isGood = React.useMemo(() => { if (!graphData) return false; return graphData.some(assessmentData => { return assessmentData.assessmentType === 'HERE' || ['THAT', 'THIS', 'OTHER'].includes(assessmentData.assessmentType); }); }, [graphData]); return ( <React.Fragment> <Drilldown animateHeight aria-label="Results" data={{ panel: { listHeader: 'Member', listItems: listItems } }} /> <br /> {!isGood ? ( <Card> <Card.Body> <Headline>Create new for selected member</Headline> <br /> <br /> <Modal open={createModal} onClose={setCreateModal} large> <Modal.Body> <CreatePvnAssessment isUserAllowedEdit={isUserAllowedEdit} memberPartyId={graphData.partyId} memberPartyIdType={graphData.partyIdType} userId={userId} handleUpdateSuccess={handleUpdateSuccess} /> </Modal.Body> </Modal> <Modal open={error} onClose={setError} small> <Modal.Body> <Headline p={15}>Record failed to update</Headline> </Modal.Body> </Modal> <Grid.Row> <Grid.Column sm="6"> <Button onClick={() => setCreateModal(true)}>Create</Button> </Grid.Column> </Grid.Row> </Card.Body> </Card> ) : null} </React.Fragment> ); }
重构说明
- 移除全局的
isGood/isSubGood状态,改为处理每个assessmentData时实时计算对应值并直接传递给子组件,规避闭包和状态更新问题。 - 用
useMemo缓存listItems和全局isGood的值,仅在依赖项变化时重新计算,提升性能。 - 解构
props简化代码,修复setIsGoog的拼写错误。 - 移除冗余的
results变量,直接返回JSX,代码逻辑更直观。
内容的提问来源于stack exchange,提问作者OpenMeyends
相关产品推荐
相关产品推荐

