Skip to content

GraphQL

概述

GraphQL 是 API 查询语言,客户端可以精确获取所需数据。

一、GraphQL vs REST

特性GraphQLREST
端点单一多个
数据获取精确字段固定结构
版本控制演进式v1/v2/v3
Over-fetching常见
Under-fetching常见

二、基础查询

graphql
# 查询
query GetUser($id: ID!) {
  user(id: $id) {
    id
    name
    posts {
      title
    }
  }
}

# 变更
mutation CreatePost($input: PostInput!) {
  createPost(input: $input) {
    id
    title
  }
}

# 订阅
subscription OnPostCreated {
  postCreated {
    id
    title
  }
}

三、Apollo Client

javascript
import { ApolloClient, InMemoryCache, gql, useQuery } from '@apollo/client';

const client = new ApolloClient({
  uri: 'https://api.example.com/graphql',
  cache: new InMemoryCache()
});

// React Hook
const GET_USERS = gql`
  query GetUsers {
    users { id name }
  }
`;

function Users() {
  const { loading, error, data } = useQuery(GET_USERS);
  
  if (loading) return <p>Loading...</p>;
  if (error) return <p>Error</p>;
  
  return data.users.map(user => <div key={user.id}>{user.name}</div>);
}

四、缓存与优化

javascript
// 缓存更新
const [createPost] = useMutation(CREATE_POST, {
  update(cache, { data: { createPost } }) {
    const { posts } = cache.readQuery({ query: GET_POSTS });
    cache.writeQuery({
      query: GET_POSTS,
      data: { posts: [...posts, createPost] }
    });
  }
});

// 乐观更新
const [updatePost] = useMutation(UPDATE_POST, {
  optimisticResponse: {
    updatePost: { id: '1', title: 'New Title', __typename: 'Post' }
  }
});

五、分页

graphql
# Cursor-based
query GetPosts($first: Int!, $after: String) {
  posts(first: $first, after: $after) {
    edges {
      node { id title }
      cursor
    }
    pageInfo {
      hasNextPage
      endCursor
    }
  }
}

面试高频题

Q1: GraphQL 优势?

精确数据获取、单一端点、强类型、自文档化。

Q2: N+1 问题?

多层嵌套查询导致多次数据库查询,使用 DataLoader 批量加载解决。

Q3: 缓存策略?

Apollo 使用 normalized cache,按 id + __typename 缓存实体。

前端面试知识库