React-Apollo 2.1中<Apollo Query>加载完成后更新父组件状态的最优方案
Apollo 加载完成后更新父组件状态的最优方案
嘿,我来给你分享几个不用让子组件监听props变化的方案,能让你的代码职责更清晰、耦合度更低!
方案1:在父组件中直接使用的Render Props
把Query组件放在父组件里,利用它的render props回调,在数据加载完成后直接更新父组件状态,子组件只负责接收数据渲染就好,完全不用处理状态逻辑。
示例代码:
import { Query } from 'react-apollo'; import gql from 'graphql-tag'; import { useState } from 'react'; // 定义你的查询 const GET_DATA_BY_ID = gql` query GetDataById($id: ID!) { data(id: $id) { id name // 其他需要的字段 } } `; function ParentComponent() { const [parentState, setParentState] = useState(null); // 假设currentId是你需要传入的查询ID const currentId = 'some-target-id'; return ( <Query query={GET_DATA_BY_ID} variables={{ id: currentId }}> {({ loading, error, data }) => { if (loading) return <div>加载中...</div>; if (error) return <div>出错了:{error.message}</div>; // 当Query加载完成拿到有效数据时,直接更新父状态 if (data?.data) { setParentState(data.data); } // 把数据传给子组件,子组件只管渲染 return <ChildComponent data={data.data} />; }} </Query> ); }
这个方案的核心是把数据处理逻辑完全放在父组件,子组件做纯UI组件,不用关心数据从哪来、什么时候更新,职责单一。
方案2:使用useQuery Hook(函数组件首选)
如果你的项目用的是函数组件,Apollo的useQuery Hook会让代码更简洁。配合useEffect监听查询返回的data变化,自动更新父组件状态。
示例代码:
import { useQuery } from '@apollo/client'; import gql from 'graphql-tag'; import { useEffect, useState } from 'react'; const GET_DATA_BY_ID = gql` query GetDataById($id: ID!) { data(id: $id) { id name } } `; function ParentComponent() { const [parentState, setParentState] = useState(null); const currentId = 'some-target-id'; // 执行查询 const { loading, error, data } = useQuery(GET_DATA_BY_ID, { variables: { id: currentId }, }); // 当data更新时(首次加载或ID变化重新查询),更新父状态 useEffect(() => { if (data?.data) { setParentState(data.data); } }, [data]); if (loading) return <div>加载中...</div>; if (error) return <div>出错了:{error.message}</div>; return <ChildComponent data={data.data} />; }
这个方案更符合React Hooks的编程范式,代码更清爽,同样不需要子组件做任何额外处理。
方案3:类组件使用graphql高阶组件(兼容旧项目)
如果你的项目还在用类组件,可以用Apollo的graphql高阶组件把查询数据注入到父组件props中,然后在componentDidUpdate里监听数据变化更新状态。
示例代码:
import { graphql, compose } from 'react-apollo'; import gql from 'graphql-tag'; import React from 'react'; const GET_DATA_BY_ID = gql` query GetDataById($id: ID!) { data(id: $id) { id name } } `; class ParentComponent extends React.Component { state = { parentState: null, }; componentDidUpdate(prevProps) { const { data } = this.props; // 当查询数据变化时(比如ID更新导致重新查询),更新父状态 if (data?.data && data.data !== prevProps.data?.data) { this.setState({ parentState: data.data }); } } render() { const { loading, error, data } = this.props; if (loading) return <div>加载中...</div>; if (error) return <div>出错了:{error.message}</div>; return <ChildComponent data={data.data} />; } } export default compose( graphql(GET_DATA_BY_ID, { options: (props) => ({ variables: { id: props.currentId } }), }) )(ParentComponent);
总结
不管用哪种方案,核心思想都是把数据查询和状态更新的逻辑放在父组件,让子组件只负责接收props渲染UI。这样就彻底摆脱了子组件监听props的需求,代码结构更清晰,维护起来也更方便。
内容的提问来源于stack exchange,提问作者Kenneth Truong
相关产品推荐
相关产品推荐

