前端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

ROS2机器人slam_toolbox建图零基础

系统:Ubuntu22.04 ROS2版本:Humble 雷达设备:rplidar_a1 一、安装必要的软件包 # 更新系统 sudo apt update # 安装slam_toolbox sudo apt install ros-humble-slam-toolbox # 安装RPLidar驱动 sudo apt install ros-humble-rplidar-ros # 安装导航相关包 sudo apt install ros-humble-navigation2 ros-humble-nav2-bringup 二、配置RPLidar_A1 创建udev规则(让系统识别雷达) # 创建udev规则 echo 'KERNEL=="ttyUSB*", ATTRS{idVendor}=="10c4", ATTRS{idProduct}

简单易学的分离式部署小米智能家居Miloco方法

一、安装环境 * Windows用户:安装WSL2以及Docker * macOS/Linux用户:安装Docker 此处不再赘述,网上随便找个教程即可。特别地,对于Windows用户来说,你需要将 WSL2 的网络模式设置为 Mirrored。 二、使用Docker部署Miloco后端 以下均为bash命令。请Windows用户进入WSL2 / Linux、macOS用户进入终端操作: mkdir miloco cd milico vi docker-compose.yml 以下是compose的内容(不会使用vi的同学可以傻瓜式操作:先按i,再使用粘贴功能,然后按冒号,输入wq然后回车,记得关闭输入法): services:backend:container_name: miloco-backend image: ghcr.nju.edu.cn/xiaomi/miloco-backend:latest network_mode:

轮腿机器人代码调试补充

轮腿机器人代码调试补充

* @Author: 星夜雨夜 * @brief: 轮腿基础代码编写调试补充,移植自达妙开源代码 * @attention:笔者默认读者已经熟练掌握机甲大师RoboMaster c型开发板例程代码的底盘代码和INS_task.c陀螺仪代码、熟练掌握各电机can协议和遥控器dbus协议。默认读者已能看懂轮腿圣经和玺佬的五连杆运动学解算与VMC。建议读者仔细研读轮腿圣经3~5遍,边看MATLAB文件和达妙开源代码,掌握轮腿调试和编写大致思路。一定要注意各状态变量的单位和正负号是否正确,轮腿调试过程中,最难之处在于极性是否正确。本车所有电机均为逆时针旋转为正方向。 !!!强烈建议读者在开发轮腿之前,先运用LQR算法完成一阶倒立摆的平衡小车(即板凳模型)的实现 !!!如果时间紧,其实完全可以不搞仿真,直接实机开调。仿真不疯,实物不一定不疯;但实物疯,仿真必疯。 调试成果展示视频链接(抖音):轮腿机器人 一阶倒立摆平衡小车参考资料: 1.本科毕设 轮腿式双足机器人 开源文件演示_哔哩哔哩_bilibili(资料在视频评论区) 2.达妙平衡小车开源:[达妙科技开源系列-平衡小车] 第一弹_哔哩