如何在React-Apollo-Hooks中正确关联useQuery与useMutation变量?
解决useQuery返回值未就绪导致useMutation变量undefined的问题
这个问题我太熟了!你踩的坑是useQuery异步特性导致的——组件刚挂载时,请求还在pending状态,data是undefined,这时候直接去取data.posts[0].author.id自然会拿到undefined,搞不好还会直接抛出Cannot read properties of undefined的错误。给你几个实用的解决办法:
1. 利用loading状态做守卫,确保数据就绪再处理
useQuery返回的loading状态就是用来帮你判断请求是否完成的。在数据加载完成前,你可以先渲染加载提示,或者不执行依赖data的逻辑:
const { data, error, loading } = useQuery(GET_POSTS, { variables: { id: props.match.params.id } }) const item = props.match.params.id // 加载中时直接返回加载组件,避免后续代码访问未就绪的data if (loading) return <div>加载中,请稍候...</div> // 处理请求错误的情况 if (error) return <div>加载帖子失败:{error.message}</div> // 到这里data肯定已经就绪了 const owner = data.posts[0].author.id const [bookItem] = useMutation(CREATE_BOOKING_MUTATION) // 调用mutation时再传入变量 const handleBook = () => { bookItem({ variables: { item, owner, startDate, endDate } }) }
2. 用可选链操作符安全访问属性,配合调用前校验
如果不想让组件暂停渲染,可以用?.可选链操作符避免访问undefined属性报错,同时在调用mutation前检查数据是否就绪:
const { data, error, loading } = useQuery(GET_POSTS, { variables: { id: props.match.params.id } }) const item = props.match.params.id // 用可选链安全获取owner,数据未就绪时会返回undefined const owner = data?.posts[0]?.author.id const [bookItem] = useMutation(CREATE_BOOKING_MUTATION) const handleBook = () => { // 调用前先校验数据是否就绪 if (loading || !owner) { alert('数据还没加载好,请稍等一下哦') return } bookItem({ variables: { item, owner, startDate, endDate } }) }
3. 给useMutation配置动态变量函数(进阶用法)
如果你希望在useMutation初始化时就关联变量,可以把variables配置成一个函数,这样每次调用mutation时都会重新计算变量值,确保拿到最新的data:
const { data, error, loading } = useQuery(GET_POSTS, { variables: { id: props.match.params.id } }) const item = props.match.params.id const [bookItem] = useMutation(CREATE_BOOKING_MUTATION, { // 用函数返回变量,每次调用都会重新求值 variables: () => ({ item, owner: data?.posts[0]?.author.id, startDate, endDate }) }) const handleBook = () => { if (loading || !data) return bookItem() }
核心总结
本质上就是要尊重useQuery的异步特性:永远不要在loading为true或者data为undefined时,直接访问data里的嵌套属性。通过状态守卫、可选链或者动态函数这几种方式,就能完美规避变量未定义的问题啦。
内容的提问来源于stack exchange,提问作者Kevvv
相关产品推荐
相关产品推荐

