如何在Next.js中用Apollo Client结合getServerSideProps实现组件无传参取数
问题描述
我正在尝试在Next.js中使用apollo-client,希望在getServerSideProps中完成数据获取。当前我有Section、Mobile两个组件以及Home页面:
- section.tsx(组件1)代码如下:
const Section = () => { return ( <div> Section </div> ); }; export default Section;
- mobile.tsx(组件2)代码如下:
const Mobile = () => { return ( <div> Mobile </div> ); }; export default Mobile;
我已将这两个组件引入Home页面(index.tsx):
const Home: NextPage = () => { return ( <Container disableGutters maxWidth="xxl"> <Section /> <Mobile /> </Container> ); }; export default Home; export const getServerSideProps: GetServerSideProps = async () => { const { data } = await client.query({ query: GET_USER_LIST }) return { props: {} } }
我的问题是:如何让Section和Mobile组件无需通过props传递,直接访问这些数据?因为组件树层级加深后,props传递会难以维护。我从Apollo文档了解到apollo-client和redux状态管理器类似,想请教是否可以实现上述需求,若可行该如何操作,若不可行有什么替代方案?
解决方案
完全可以实现你的需求,利用Apollo Client的缓存机制和组件内查询能力即可,无需手动传props,具体步骤如下:
1. 确保Apollo Client全局配置完成
首先要在_app.tsx中用ApolloProvider全局包裹应用,让所有组件都能访问到Apollo Client实例:
import { ApolloProvider } from '@apollo/client'; import client from '../lib/apollo-client'; function MyApp({ Component, pageProps }) { return ( <ApolloProvider client={client}> <Component {...pageProps} /> </ApolloProvider> ); } export default MyApp;
2. 在getServerSideProps中预取数据并写入缓存
你现在的getServerSideProps已经执行了查询,Apollo Client默认会把查询结果自动存入缓存,只要你的client实例是全局共享的,这一步无需额外修改。如果需要确认,可以保持现有代码:
export const getServerSideProps: GetServerSideProps = async () => { await client.query({ query: GET_USER_LIST }); return { props: {} }; };
3. 子组件直接从缓存读取数据
在Section和Mobile组件中使用useQuery钩子查询相同的GET_USER_LIST,Apollo会自动从缓存读取数据,不会发起新的网络请求:
修改后的Section组件:
import { useQuery } from '@apollo/client'; import { GET_USER_LIST } from '../graphql/queries'; const Section = () => { const { data, loading, error } = useQuery(GET_USER_LIST); if (loading) return <div>加载中...</div>; if (error) return <div>错误:{error.message}</div>; return ( <div> Section - 用户列表:{JSON.stringify(data.userList)} </div> ); }; export default Section;
修改后的Mobile组件:
import { useQuery } from '@apollo/client'; import { GET_USER_LIST } from '../graphql/queries'; const Mobile = () => { const { data, loading, error } = useQuery(GET_USER_LIST); if (loading) return <div>加载中...</div>; if (error) return <div>错误:{error.message}</div>; return ( <div> Mobile - 用户列表:{JSON.stringify(data.userList)} </div> ); }; export default Mobile;
替代方案
如果不想在每个组件中写useQuery,可以用以下两种方式:
- React Context:在
getServerSideProps中获取数据后,存入自定义Context,子组件通过useContext直接读取。 - 直接读取Apollo缓存:用
useApolloClient获取客户端实例,调用readQuery读取缓存数据,注意这种方式需要自己处理数据不存在的情况:
import { useApolloClient } from '@apollo/client'; import { GET_USER_LIST } from '../graphql/queries'; const Section = () => { const client = useApolloClient(); const data = client.readQuery({ query: GET_USER_LIST }); return ( <div> Section - 用户列表:{data ? JSON.stringify(data.userList) : '无数据'} </div> ); };
内容的提问来源于stack exchange,提问作者Md Ali
相关产品推荐
相关产品推荐

