前端GraphQL客户端:优雅地获取数据
毒舌时刻
前端GraphQL?这不是后端的事吗?
"REST API就够了,为什么要用GraphQL"——结果前端需要多次请求,数据冗余,
"GraphQL太复杂了,我学不会"——结果错过了更灵活的数据获取方式,
"我直接用fetch请求GraphQL,多简单"——结果缺少缓存、错误处理等功能。
醒醒吧,GraphQL不是后端的专利,前端也需要专业的客户端工具!
为什么你需要这个?
- 减少网络请求:一次请求获取所有需要的数据
- 数据精确:只获取需要的数据,避免冗余
- 类型安全:自动生成TypeScript类型
- 缓存优化:智能缓存,减少重复请求
- 开发效率:简化数据获取逻辑
反面教材
// 反面教材:直接使用fetch请求GraphQL async function fetchGraphQL(query, variables) { const response = await fetch('https://api.example.com/graphql', { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify({ query, variables }), }); const data = await response.json(); if (data.errors) { console.error('GraphQL errors:', data.errors); throw new Error('GraphQL request failed'); } return data.data; } // 反面教材:重复请求相同数据 async function loadUserAndPosts() { // 第一次请求用户信息 const { user } = await fetchGraphQL(` query GetUser($id: ID!) { user(id: $id) { id name email } } `, { id: 1 }); // 第二次请求用户的帖子 const { user: userWithPosts } = await fetchGraphQL(` query GetUserWithPosts($id: ID!) { user(id: $id) { id posts { id title content } } } `, { id: 1 }); return { user, posts: userWithPosts.posts }; }
正确的做法
// 正确的做法:使用Apollo Client import { ApolloClient, InMemoryCache, gql } '/client'; // 创建Apollo Client实例 const client = new ApolloClient({ uri: , cache: new (), headers: { authorization: localStorage.() || } }); // 定义查询 const GET_USER_WITH_POSTS = gql` query GetUserWithPosts($id: ID!) { user(id: $id) { id name email posts { id title createdAt } } } `; // 定义变更 const CREATE_POST = gql` mutation CreatePost($: PostInput!) { createPost(: $input) { id title createdAt } } `; // 在React组件中使用 import React 'react'; import { useQuery, useMutation } '/client'; function UserProfile({ userId }) { // 使用useQuery钩子获取数据 const { loading, error, data, refetch } = useQuery(GET_USER_WITH_POSTS, { variables: { id: userId }, // 缓存策略 fetchPolicy: }); // 使用useMutation钩子执行变更 const = useMutation(CREATE_POST, { // 变更后更新缓存 update(cache, { data: { createPost } }) { const { user } = cache({ query: GET_USER_WITH_POSTS, variables: { id: userId } }); cache({ query: GET_USER_WITH_POSTS, variables: { id: userId }, data: { user: { .., posts: [...user.posts, createPost] } } }); } }); if (loading) return <>加载中...</>; if (error) return <>错误:{error}</>; const handleCreatePost = async (title, ) => { await createPost({ variables: { : { title, , userId } } }); }; return ( <> <>{data}</> <>{data}</> <>帖子</> <> {data(post => ( < key={post}> <>{post}</> <>{post}</> <>{post}</> </> ))} </> < onClick={() => refetch()}>刷新</> < onClick={() => handleCreatePost('新帖子', '帖子内容')} disabled={creating} > {creating ? '创建中...' : } </> </> ); } // 正确的做法:使用URQL import { createClient, gql } 'urql'; // 创建URQL客户端 const client = createClient({ url: , fetchOptions: () => ({ headers: { authorization: localStorage.() || } }) }); // 在React组件中使用 import React 'react'; import { useQuery, useMutation } 'urql'; function UserList() { const = useQuery({ query: gql` query GetUsers { users { id name email } } ` }); const { data, fetching, error } = result; if (fetching) return <>加载中...</>; if (error) return <>错误:{error}</>; return ( <> <>用户列表</> <> {data(user => ( < key={user}> {user} - {user} </> ))} </> < onClick={() => reexecuteQuery()}>刷新</> </> ); } // 正确的做法:使用Relay import { Environment, Network, RecordSource, Store, useLazyLoadQuery, graphql } 'relay-runtime'; // 创建Relay环境 function fetchQuery(operation, variables) { return fetch('https://api.example.com/graphqlPOSTContent-Typeapplication/jsontoken

