等待useQuery返回数据后写入React状态的报错排查
解决React中Apollo Client查询数据存入State后渲染报错的问题
问题原因
你添加React State存储查询数据后出现TypeError: Cannot read properties of null (reading 'firstName'),核心原因是:
- 初始State设为
null,虽然有loading判断,但loading结束后,useEffect是在组件渲染完成后才执行的——这意味着第一次渲染时participant还是初始的null,传给ProfileGeneral组件后,子组件直接访问participant.firstName就会触发空值报错。 - 原代码直接从
data同步解构participant,loading结束后data已就绪,所以不会有问题;但通过useEffect异步更新State,就出现了渲染时机不匹配的问题。
解决方案
方案1:渲染前校验State值
在渲染子组件前,先确认participant有值,避免传递空值:
return ( <div> {/* 只有participant存在时才渲染子组件 */} {participant ? <ProfileGeneral participant={participant} /> : <div>Loading...</div>} </div> )
方案2:用useQuery的onSuccess回调同步更新State
不需要依赖useEffect,直接利用Apollo useQuery的onSuccess回调,查询成功后立即更新State,保证数据同步:
import { useQuery } from '@apollo/client'; import { SINGLE_PARTICIPANT_QUERY } from 'queries/participantQueries'; import { ProfileGeneral } from './ProfileGeneral'; import { useState } from 'react'; const ProfilePage = ({ id }) => { const [participant, setParticipant] = useState(null); const { loading, error } = useQuery(SINGLE_PARTICIPANT_QUERY, { variables: { id }, onSuccess: (data) => { data?.participant && setParticipant(data.participant); } }); if (loading) { return <div>Loading</div>; } if (error) { return <div>{error.message}</div>; } if (!participant) { return <div>No participant data found</div>; } return ( <div> <ProfileGeneral participant={participant} /> </div> ) }
方案3:子组件内部做空值处理
在ProfileGeneral组件内部对接收的participant做校验,从根源避免空值访问:
// ProfileGeneral.jsx const ProfileGeneral = ({ participant }) => { if (!participant) { return <div>Loading participant info...</div>; } return ( <div> <p>First Name: {participant.firstName}</p> {/* 其他表单内容 */} </div> ) }
额外优化:清理useEffect的无效依赖
如果一定要保留useEffect,注意不要把participant放进依赖数组(会触发无限循环),只保留data即可:
useEffect(() => { if (data && data.participant) { setParticipant(data.participant); } }, [data]); // 移除participant依赖
内容的提问来源于stack exchange,提问作者kftb
相关产品推荐
相关产品推荐

