前端GraphQL客户端:优雅地获取数据

前端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 } from '@apollo/client'; // 创建Apollo Client实例 const client = new ApolloClient({ uri: 'https://api.example.com/graphql', cache: new InMemoryCache(), headers: { authorization: localStorage.getItem('token') || '' } }); // 定义查询 const GET_USER_WITH_POSTS = gql` query GetUserWithPosts($id: ID!) { user(id: $id) { id name email posts { id title content createdAt } } } `; // 定义变更 const CREATE_POST = gql` mutation CreatePost($input: PostInput!) { createPost(input: $input) { id title content createdAt } } `; // 在React组件中使用 import React from 'react'; import { useQuery, useMutation } from '@apollo/client'; function UserProfile({ userId }) { // 使用useQuery钩子获取数据 const { loading, error, data, refetch } = useQuery(GET_USER_WITH_POSTS, { variables: { id: userId }, // 缓存策略 fetchPolicy: 'cache-and-network' }); // 使用useMutation钩子执行变更 const [createPost, { loading: creating }] = useMutation(CREATE_POST, { // 变更后更新缓存 update(cache, { data: { createPost } }) { const { user } = cache.readQuery({ query: GET_USER_WITH_POSTS, variables: { id: userId } }); cache.writeQuery({ query: GET_USER_WITH_POSTS, variables: { id: userId }, data: { user: { ...user, posts: [...user.posts, createPost] } } }); } }); if (loading) return <div>加载中...</div>; if (error) return <div>错误:{error.message}</div>; const handleCreatePost = async (title, content) => { await createPost({ variables: { input: { title, content, userId } } }); }; return ( <div> <h2>{data.user.name}</h2> <p>{data.user.email}</p> <h3>帖子</h3> <ul> {data.user.posts.map(post => ( <li key={post.id}> <h4>{post.title}</h4> <p>{post.content}</p> <p>{post.createdAt}</p> </li> ))} </ul> <button onClick={() => refetch()}>刷新</button> <button onClick={() => handleCreatePost('新帖子', '帖子内容')} disabled={creating} > {creating ? '创建中...' : '创建帖子'} </button> </div> ); } // 正确的做法:使用URQL import { createClient, gql } from 'urql'; // 创建URQL客户端 const client = createClient({ url: 'https://api.example.com/graphql', fetchOptions: () => ({ headers: { authorization: localStorage.getItem('token') || '' } }) }); // 在React组件中使用 import React from 'react'; import { useQuery, useMutation } from 'urql'; function UserList() { const [result, reexecuteQuery] = useQuery({ query: gql` query GetUsers { users { id name email } } ` }); const { data, fetching, error } = result; if (fetching) return <div>加载中...</div>; if (error) return <div>错误:{error.message}</div>; return ( <div> <h2>用户列表</h2> <ul> {data.users.map(user => ( <li key={user.id}> {user.name} - {user.email} </li> ))} </ul> <button onClick={() => reexecuteQuery()}>刷新</button> </div> ); } // 正确的做法:使用Relay import { Environment, Network, RecordSource, Store, useLazyLoadQuery, graphql } from 'relay-runtime'; // 创建Relay环境 function fetchQuery(operation, variables) { return fetch('https://api.example.com/graphql', { method: 'POST', headers: { 'Content-Type': 'application/json', authorization: localStorage.getItem('token') || '' }, body: JSON.stringify({ query: operation.text, variables, }), }).then(response => { return response.json(); }); } const environment = new Environment({ network: Network.create(fetchQuery), store: new Store(new RecordSource()), }); // 定义查询 const UserQuery = graphql` query UserQuery($id: ID!) { user(id: $id) { id name email posts { edges { node { id title content } } } } } `; // 在React组件中使用 function UserDetail({ userId }) { const data = useLazyLoadQuery( UserQuery, { id: userId } ); return ( <div> <h2>{data.user.name}</h2> <p>{data.user.email}</p> <h3>帖子</h3> <ul> {data.user.posts.edges.map(edge => ( <li key={edge.node.id}> <h4>{edge.node.title}</h4> <p>{edge.node.content}</p> </li> ))} </ul> </div> ); } 

毒舌点评

看看,这才叫前端GraphQL客户端!不是简单地使用fetch请求,而是使用Apollo Client、URQL或Relay等专业的客户端工具。

记住,GraphQL客户端不仅仅是发送请求,还包括缓存管理、错误处理、类型生成等功能。这些工具可以大大简化你的前端代码,提高开发效率。

所以,别再觉得GraphQL复杂了,使用专业的客户端工具,让数据获取变得更加优雅!

总结

  • Apollo Client:功能强大,生态丰富,适合大型应用
  • URQL:轻量级,API简洁,适合中小型应用
  • Relay:Facebook开发,性能优异,适合大型应用
  • 缓存管理:智能缓存,减少重复请求
  • 类型安全:自动生成TypeScript类型
  • 错误处理:统一的错误处理机制
  • 变更管理:执行GraphQL变更并更新缓存
  • 开发工具:GraphQL Playground、Apollo DevTools等

前端GraphQL客户端,让数据获取变得更加优雅!

Read more

彻底关闭Win10中烦人的365 Copilot弹窗的6种方法

快速体验 1. 打开 InsCode(快马)平台 https://www.inscode.net 2. 点击'项目生成'按钮,等待项目生成完整后预览效果 输入框输入如下内容 帮我开发一个Windows系统优化小工具,用于帮助普通用户一键禁用各类系统弹窗和推送功能。系统交互细节:1.提供常见弹窗类型选择 2.显示当前系统状态 3.一键禁用功能 4.支持恢复默认设置。注意事项:需要管理员权限运行 最近很多Win10用户在系统升级后都遇到了Microsoft 365 Copilot频繁弹窗的问题,这个功能虽然智能,但频繁的打扰确实影响工作效率。经过实测,我总结了6种有效的关闭方法,从简单隐藏到彻底禁用一应俱全。 1. 任务栏临时隐藏是最简单的解决方案,只需右键任务栏取消勾选相关选项。但这个方法只是隐藏入口,Copilot功能仍在后台运行。 2. 组策略彻底禁用是最推荐的方式,通过系统内置的组策略编辑器可以完全关闭Copilot。操作时需要管理员权限,设置完成后需要重启生效。这个方法禁用后连快捷键都会失效,

FPGA开发环境搭建:Vivado 2019.2超详细版安装教程

FPGA开发环境搭建:Vivado 2019.2超详细安装与授权配置指南 你是否曾在准备开启FPGA设计之旅时,被Vivado复杂的安装流程卡住?下载了几十GB的安装包,却在“Creating directories…”界面卡死半小时;好不容易装完启动,却发现提示“Feature is not licensed”,连比特流都无法生成? 别担心——这几乎是每一位初学者都会经历的“入门劫”。本文将带你 从零开始、一步不落地完成 Vivado 2019.2 的完整部署 ,涵盖系统准备、组件选择、破解补丁应用、许可证加载以及常见问题的实战解决方案。无论你是高校学生、电子竞赛选手,还是刚接触嵌入式开发的工程师,都能凭借这份教程顺利点亮你的第一个LED。 为什么是 Vivado 2019.2? 尽管Xilinx(现为AMD)已推出更新版本如2023.x系列,但 Vivado 2019.2 依然是当前最稳定、兼容性最强、

AM32固件深度探索:从零开始构建高性能无人机电调系统

AM32固件深度探索:从零开始构建高性能无人机电调系统 【免费下载链接】AM32-MultiRotor-ESC-firmwareFirmware for stm32f051 based speed controllers for use with mutirotors 项目地址: https://gitcode.com/gh_mirrors/am/AM32-MultiRotor-ESC-firmware 嘿,无人机爱好者们!是否曾经为电调启动时的剧烈抖动而烦恼?是否想要让飞行更加平稳顺滑?今天,让我们一起深入探索AM32固件,这个专为STM32处理器设计的开源无刷电机控制解决方案,它将彻底改变你的飞行体验! 为什么AM32固件值得你关注? 想象一下:你的无人机在启动时就像丝绸般平滑,飞行过程中响应灵敏得如同你的思维延伸。AM32固件正是为此而生,它不仅仅是一个固件,更是一套完整的电机控制生态系统。 三大核心优势: * 🚀 极致性能:相比传统固件,响应速度提升300% * 🎯 精准控制:正弦波算法让电机运行更加平稳 * 🔧 高度可定制:支持多种硬件平台和个性化配

Python——搭建一个有记忆,可以人工干预转人工,调用搜索工具的机器人

Python——搭建一个有记忆,可以人工干预转人工,调用搜索工具的机器人

Python——搭建一个有记忆,可以人工干预转人工,调用搜索工具的机器人 前言 在看了LangGraph官网:https://github.langchain.ac.cn/langgraph/concepts/why-langgraph/ 的教程之后,也是跟着教程做了一个简单的聊天机器人作为初始的一个计划,为啥学的是python的LangGraph呢?我本身学习的就是JAVA,实习找的也是JAVA的工作,但是JAVA确实太卷了,本人之前没有背过八股文,有幸进入一家外包公司java实习,也参与过项目的开发,但是现在的AI发展的很快,我一开始实习的时候,会以为我可能跟不上,因为这是我的第一段实习,可结果确实有着AI的开发辅助,我就发现,很快就可以上手开发,但是要注意提示词,并且规范好,开发的代码格式等。然后又对大模型应用开发这些感兴趣,于是开始慢慢的学了起来。 前置准备 前置准备分为环境和APIkey的获取,这些就不再进行重复了,都放在前面的文章里面有,大家感兴趣的可以看看就行了,包括.env我们也不再进行重复 环境配置 python3.12(python 3.9+)