使用React和GraphQL进行CRUD:完整教程与示例

使用React和GraphQL进行CRUD:完整教程与示例

在本教程中,我们将向您展示如何使用GraphQL和React实现简单的端到端CRUD操作。我们将介绍使用React Hooks读取和修改数据的简单示例。我们还将演示如何使用Apollo Client实现身份验证、错误处理、缓存和乐观UI。

什么是React?

React是一个用于构建用户界面的JavaScript库。它旨在帮助构建应用程序的前端部分,包括处理Web和移动应用的视图层。

React是基于组件的,这意味着React应用程序的各个部分被分解成较小的组件,然后在更高级别的组件中组织。这些更高级别的组件定义了应用程序的最终结构。

React支持可重用组件,因此您可以创建一个组件,并在应用程序的不同部分多次使用。这有助于减少冗余代码,使代码更易于维护,遵循DRY原则。

什么是GraphQL?

GraphQL是一种用于API的查询语言,也是一个用现有数据来实现查询的运行时。简单来说,GraphQL是一种描述如何请求数据的语法。它通常用于从服务器加载数据到客户端。

GraphQL通过将所有请求抽象到一个端点来简化API的构建。与传统的REST API不同,它是声明式的,这意味着请求的内容会被返回。

何时使用GraphQL

当然,并不是所有项目都需要GraphQL——它只是一个用于整合数据的工具。GraphQL有定义良好的模式,因此我们可以确定不会过度获取数据。但是,如果我们已经有一个稳定的RESTful API系统,并且只依赖单一数据源的数据,那么我们不需要GraphQL。

例如,假设我们正在为自己创建一个博客,并决定在单一的MongoDB数据库中存储、检索和通信数据。在这种情况下,我们没有做任何复杂的架构设计,不需要GraphQL。

另一方面,假设我们有一个依赖多个数据源(如MongoDB、MySQL、Postgres和其他API)的完整产品。在这种情况下,我们应该使用GraphQL。

例如,如果我们在设计一个作品集网站,并希望从社交媒体和GitHub获取数据(以显示贡献),并且我们还有自己的数据库来维护博客,我们可以使用GraphQL来编写业务逻辑和模式。它将数据整合为单一的真实来源。

一旦我们有了解决函数来将正确的数据分发到前端,我们将能够轻松地在单一来源中管理数据。

什么是CRUD?

在构建API时,您希望您的模型提供四个基本功能:它应该能够创建、读取、更新和删除资源。这一组基本操作通常被称为CRUD。

RESTful API通常使用HTTP请求。在REST环境中,四个最常见的HTTP方法是GETPOSTPUTDELETE,这是开发者可以用来创建CRUD系统的方法。

使用graphql-server进行CRUD

在本节中,我们将介绍一些GraphQL CRUD示例,以帮助您了解在React和GraphQL应用程序中CRUD操作的工作方式。

设置服务器

我们将使用express-graphql启动一个简单的GraphQL服务器,并将其连接到MySQL数据库。源代码和MySQL文件在这个仓库中。

GraphQL服务器是基于模式和解析器构建的。首先,我们构建一个模式(定义类型、查询、变更和订阅)。该模式描述了整个应用程序结构。

其次,对于模式中定义的内容,我们构建相应的解析器来计算和分发数据。解析器将动作映射到函数;对于在类型定义中声明的每个查询,我们创建一个解析器来返回数据。

最后,通过定义端点并传递配置来完成服务器设置。我们将/graphql初始化为应用程序的端点。对于graphqlHTTP中间件,我们传递构建的模式和根解析器。

除了模式和根解析器外,我们还启用了GraphiQL开发工具。GraphiQL是一个交互式的浏览器内GraphQL IDE,可以帮助我们玩转构建的GraphQL查询。

var express = require('express');
var graphqlHTTP = require('express-graphql');
var { buildSchema } = require('graphql');var schema = buildSchema(`type Query {hello: String}
`);var root = {hello: () => "World"
};var app = express();app.use('/graphql', graphqlHTTP({schema: schema,rootValue: root,graphiql: true,
}));app.listen(4000);console.log('Running a GraphQL API server at localhost:4000/graphql');

一旦服务器准备就绪,运行node index.js将启动服务器在http://localhost:4000/graphql。我们可以查询hello并获得字符串“World”作为响应。

连接数据库

我要建立与MySQL数据库的连接,如下所示:

var mysql = require('mysql');app.use((req, res, next) => {req.mysqlDb = mysql.createConnection({host     : 'localhost',user     : 'root',password : '',database : 'userapp'});req.mysqlDb.connect();next();
});

我们可以连接多个数据库/数据源,并在解析器中整合它们。我在这里连接了一个MySQL数据库。本文中使用的数据库转储在GitHub仓库中。

使用GraphQL读取和写入数据

我们使用查询和变更来读取和修改数据源中的数据。在这个例子中,我定义了一个通用的queryDB函数来帮助查询数据库。

查询

所有的SELECT语句(或读取操作)用于列出和查看数据,放入type Query类型定义中。我们在这里定义了两个查询:一个用于列出数据库中的所有用户,另一个用于按ID查看单个用户。

  1. **列出数据:**为了列出用户,我们定义了一个GraphQL模式对象类型User,它表示我们可以从getUsers查询中获取或期望的内容。然后我们定义getUsers查询来返回一个用户数组。
  2. **查看单个记录:**为了查看单个记录,我们使用getUserInfo查询定义一个参数id。它查询数据库中的特定ID并将数据返回到前端。

GraphiQL演示返回用户数组

现在我们已经组合了查询来获取所有记录并按ID查看记录,当我们尝试从GraphiQL查询用户时,它将在屏幕上列出一个用户数组!

查询

var schema = buildSchema(`type User {id: Stringname: Stringjob_title: Stringemail: String}type Query {getUsers: [User],getUserInfo(id: Int) : User}
`);const queryDB = (req, sql, args) => new Promise((resolve, reject) => {req.mysqlDb.query(sql, args, (err, rows) => {if (err)return reject(err);rows.changedRows || rows.affectedRows || rows.insertId ? resolve(rows) : resolve(rows[0]);});
});var root = {getUsers: (args, req) => {return queryDB(req, `SELECT * FROM user`);},getUserInfo: (args, req) => {return queryDB(req, `SELECT * FROM user WHERE id=?`, [args.id]);}
};app.use('/graphql', graphqlHTTP({schema: schema,rootValue: root,graphiql: true
}));

变更

在变更部分中,我们将执行以下操作:创建、更新和删除记录。变更按类型定义,对应于数据库中用户模式的对象类型。

type Mutation {createUser(name: String!, job_title: String!, email: String!): UserupdateUser(id: Int!, name: String, job_title: String, email: String): StringdeleteUser(id: Int!): String
}

我定义了一个带有三个参数的createUser变更来将数据插入数据库中。updateUser使用id标识符来修改表中的用户记录,deleteUser使用id从数据库中删除记录。

const queryDB = (req, sql, args) => new Promise((resolve, reject) => {req.mysqlDb.query(sql, args, (err, rows) => {if (err)return reject(err);rows.changedRows || rows.affectedRows || rows.insertId ? resolve(rows) : resolve(rows[0]);});
});const createDB = (req, sql, args) => new Promise((resolve, reject) => {req.mysqlDb.query(sql, args, (err, rows) => {if (err)return reject(err);args[0].id = rows.insertId;resolve(args[0]);});
});var root = {getUsers: (args, req) => {return queryDB(req, `SELECT * FROM user`);},getUserInfo: (args, req) => {return queryDB(req, `SELECT * FROM user WHERE id=?`, [args.id]);},createUser: (args, req) => {return createDB(req, `INSERT INTO user SET ?`, [args]);},updateUser: (args, req) => {return queryDB(req, `UPDATE user SET ? WHERE id=?`, [args, args.id]).then((res) => "Successfully updated user").catch((err) => "Cannot update user");},deleteUser: (args, req) => {return queryDB(req, `DELETE FROM user WHERE id=?`, [args.id]).then((res) => "Successfully deleted user").catch((err) => "Cannot delete user");}
};app.use('/graphql', graphqlHTTP({schema: schema,rootValue: root,graphiql: true
}));

在React中使用graphql-client进行CRUD

这节将使用React与GraphQL客户端整合。我们将使用Apollo客户端和GraphQL查询来从GraphQL API中读取数据并更新UI。Apollo客户端的作用类似于浏览器的Fetch API,但它是为GraphQL设计的。

设置Apollo客户端

首先,确保安装了以下包:

npm i react-apollo graphql-tag apollo-boost apollo-client apollo-cache-inmemory apollo-link-http

初始化Apollo客户端并为应用程序提供客户端对象:

import ApolloClient from "apollo-boost";
import { ApolloProvider } from "react-apollo";
import React from "react";
import ReactDOM from "react-dom";
import App from "./App";const client = new ApolloClient({uri: "http://localhost:4000/graphql"
});ReactDOM.render(<ApolloProvider client={client}><App /></ApolloProvider>,document.getElementById("root")
);

列出数据

为了列出数据,我们首先创建一个GraphQL查询,然后将其传递给React组件。我们可以使用useQuery钩子来执行查询并返回结果。

import React from "react";
import gql from "graphql-tag";
import { useQuery } from "react-apollo";const GET_USERS = gql`query {getUsers {idnamejob_titleemail}}
`;const UserList = () => {const { loading, error, data } = useQuery(GET_USERS);if (loading) return <p>Loading...</p>;if (error) return <p>Error :(</p>;return (<div>{data.getUsers.map(user => (<div key={user.id}><p>{user.name}</p><p>{user.job_title}</p><p>{user.email}</p></div>))}</div>);
};export default UserList;

创建用户

为了创建新用户,我们创建一个变更并将其传递给组件。我们可以使用useMutation钩子来执行变更并返回结果。

import React from "react";
import gql from "graphql-tag";
import { useMutation } from "react-apollo";const CREATE_USER = gql`mutation CreateUser($name: String!, $job_title: String!, $email: String!) {createUser(name: $name, job_title: $job_title, email: $email) {idnamejob_titleemail}}
`;const CreateUser = () => {let name, job_title, email;const [createUser] = useMutation(CREATE_USER);return (<div><formonSubmit={e => {e.preventDefault();createUser({ variables: { name: name.value, job_title: job_title.value, email: email.value } });name.value = "";job_title.value = "";email.value = "";}}><input ref={node => { name = node; }} placeholder="Name" /><input ref={node => { job_title = node; }} placeholder="Job Title" /><input ref={node => { email = node; }} placeholder="Email" /><button type="submit">Add User</button></form></div>);
};export default CreateUser;

更新和删除用户

类似地,您可以创建更新和删除用户的组件。使用useMutation钩子传递GraphQL变更并返回结果。

import React from "react";
import gql from "graphql-tag";
import { useMutation } from "react-apollo";const UPDATE_USER = gql`mutation UpdateUser($id: Int!, $name: String, $job_title: String, $email: String) {updateUser(id: $id, name: $name, job_title: $job_title, email: $email)}
`;const DELETE_USER = gql`mutation DeleteUser($id: Int!) {deleteUser(id: $id)}
`;const UpdateUser = () => {let id, name, job_title, email;const [updateUser] = useMutation(UPDATE_USER);return (<div><formonSubmit={e => {e.preventDefault();updateUser({ variables: { id: parseInt(id.value), name: name.value, job_title: job_title.value, email: email.value } });id.value = "";name.value = "";job_title.value = "";email.value = "";}}><input ref={node => { id = node; }} placeholder="ID" /><input ref={node => { name = node; }} placeholder="Name" /><input ref={node => { job_title = node; }} placeholder="Job Title" /><input ref={node => { email = node; }} placeholder="Email" /><button type="submit">Update User</button></form></div>);
};const DeleteUser = () => {let id;const [deleteUser] = useMutation(DELETE_USER);return (<div><formonSubmit={e => {e.preventDefault();deleteUser({ variables: { id: parseInt(id.value) } });id.value = "";}}><input ref={node => { id = node; }} placeholder="ID" /><button type="submit">Delete User</button></form></div>);
};export { UpdateUser, DeleteUser };

总结

在本教程中,我们展示了如何使用React和GraphQL进行CRUD操作。我们设置了GraphQL服务器,连接到MySQL数据库,定义了查询和变更,并使用Apollo客户端在React应用中执行CRUD操作。希望这能帮助您更好地理解和实现React和GraphQL的集成。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/351327.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

用python纯手写一个日历

一、代码 # 月份名称数组 months ["January", "February", "March", "April", "May", "June","July", "August", "September", "October", "November", &qu…

【Python/Pytorch - 网络模型】-- TV Loss损失函数

文章目录 文章目录 00 写在前面01 基于Pytorch版本的TV Loss代码02 论文下载 00 写在前面 在医学图像重建过程中&#xff0c;经常在代价方程中加入TV 正则项&#xff0c;该正则项作为去噪项&#xff0c;对于重建可以起到很大帮助作用。但是对于一些纹理细节要求较高的任务&am…

20.1 JSON-JSON接口以及在Go语言中使用JSON

1. 简介 JSON即JavaScript对象表示法(JavaScript Object Notation)&#xff0c;是一种用于存储和交换数据的格式&#xff0c;是一种可供人类阅读和理解的纯文本格式。 JSON既可以键值对的形式&#xff0c;也可以数组的形式&#xff0c;表示数据。 JSON最初是JavaScript的一个…

流媒体传输协议HTTP-FLV、WebSocket-FLV、HTTP-TS 和 WebSocket-TS的详细介绍、应用场景及对比

一、前言 HTTP-FLV、WS-FLV、HTTP-TS 和 WS-TS 是针对 FLV 和 TS 格式视频流的不同传输方式。它们通过不同的协议实现视频流的传输&#xff0c;以满足不同的应用场景和需求。接下来我们对这些流媒体传输协议进行剖析。 二、传输协议 1、HTTP-FLV 介绍&#xff1a;基于 HTTP…

【宠粉赠书】科研绘图神器:MATLAB科技绘图与数据分析

小智送书第二期~ 为了回馈粉丝们的厚爱&#xff0c;今天小智给大家送上一套科研绘图的必备书籍——MATLAB科技绘图与数据分析。下面我会详细给大家介绍这套图书&#xff0c;文末留有领取方式。 图书介绍 《MATLAB科技绘图与数据分析》是一本综合性强、内容丰富的书籍&#x…

实践分享:鸿蒙跨平台开发实例

先来理解什么是跨平台 提到跨平台&#xff0c;要先理解什么是“平台”&#xff0c;这里的平台&#xff0c;就是指应用程序的运行环境&#xff0c;例如操作系统&#xff0c;或者是Web浏览器&#xff0c;具体的像HarmonyOS、Android、iOS、或者浏览器&#xff0c;都可以叫做平台…

Python读取wps中的DISPIMG图片格式

需求&#xff1a; 读出excel的图片内容&#xff0c;这放在微软三件套是很容易的&#xff0c;但是由于wps的固有格式&#xff0c;会出现奇怪的问题&#xff0c;只能读出&#xff1a;类似于 DISPIMG(“ID_2B83F9717AE1XXXX920xxxx644C80DB1”,1) 【该DISPIMG函数只有wps才拥有】 …

阿里云服务器-Linux搭建fastDFS文件服务器

阿里云官网购买服务器&#xff0c;一般会有降价活动&#xff0c;这两天就发现有活动&#xff0c;99计划活动&#xff08;在活动期内&#xff0c;续费都是99元&#xff09; 阿里云官网-云服务器ECS 在这里&#xff0c;我购买了这台服务器&#xff0c;活动期内续费每年99元&…

javaweb 期末复习

1. JDBC数据库连接的实现逻辑与步骤以及JDBC连接配置&#xff08;单列模式&#xff09; public class JDBCUtil {// 这些换成自己的数据库 private static final String DB_URL "jdbc:mysql://localhost:3306/你的数据库名称";private static final String USER &q…

10分钟部署一个个人博客

关于vuepress这里没必要过多介绍&#xff0c;感兴趣的可以直接去官网了解&#xff0c;下面是官网首页地址截图 &#xff1a;https://v2.vuepress.vuejs.org/zh/ 透过这张图&#xff0c;我们也可以大致的对这个框架的特点有一定的认识&#xff0c;这就够了。其他的东西我们在使用…

vue3+ Element-Plus 点击勾选框往input中动态添加多个tag

实现效果&#xff1a; template&#xff1a; <!--产品白名单--><div class"con-item" v-if"current 0"><el-form-item label"平台名称"><div class"contaion" click"onclick"><!-- 生成的标签 …

WPF界面设计

1、使用C#-WPF实现抽屉效果-炫酷漂亮的侧边栏导航菜单-SplitViewMD主题重绘原生控件的美观效果-提供源码Demo下载 码源地址&#xff1a;https://download.csdn.net/download/Prince999999/89424685 2、使用C#-WPF实现抽屉效果-菜单导航功能实现&#xff0c;常规的管理系统应该…

使用itextPDF实现PDF电子公章工具类

一、制作公章 在线网站&#xff1a;印章生成器 - Kalvin在线工具 (kalvinbg.cn) 然后对公章进行下载保存 盖章图片&#xff1a; 二、生成数字签名 2.1&#xff1a; java工具keytool生成p12数字证书文件 Keytool是用于管理和证书的工具&#xff0c;位于%JAVA_HOME%/bin目录。…

【Python】Python 2 测试网络连通性脚本

文章目录 前言1. 命令行传参2. 代码 前言 最近在只有python2的服务器上部署服务&#xff0c;不能用三方类库&#xff0c;这里出于好奇心学习下python。这里简单做个脚本&#xff0c;实现了检验网络连通性的功能&#xff08;类似于curl&#xff09;。 1. 命令行传参 使用命令…

和鲸科技执行总裁殷自强:面向空间数据协同分析场景的模型生命周期管理方法

导读&#xff1a; 由 ACM SIGSPATIAL 中国分会主办的第五届空间数据智能学术会议&#xff08;SpatialDI 2024&#xff09;于 2024 年 4 月 25 日- 27 日在南京圆满召开&#xff0c;主题为“ AGI 时代下的空间数据智能”&#xff0c;旨在深入推动空间数据智能研究的理论进步与应…

TIM—通用定时器高级定时器

通用/高级定时器的功能 在基本定时器功能的基础上新增功能&#xff1a; 通用定时器有4个独立通道&#xff0c;且每个通道都可以用于下面功能。 &#xff08;1&#xff09;输入捕获&#xff1a;测量输入信号的周期和占空比等。 &#xff08;2&#xff09;输出比较&#xff1a;产…

115.网络游戏逆向分析与漏洞攻防-邮件系统数据分析-调试优化结构体类型数据的创建

免责声明&#xff1a;内容仅供学习参考&#xff0c;请合法利用知识&#xff0c;禁止进行违法犯罪活动&#xff01; 如果看不懂、不知道现在做的什么&#xff0c;那就跟着做完看效果 现在的代码都是依据数据包来写的&#xff0c;如果看不懂代码&#xff0c;就说明没看懂数据包…

macOS Sequoia 将 Mac 生产力与智能化提升至全新高度 (macOS 15 ISO、IPSW、PKG 下载)

macOS Sequoia 将 Mac 生产力与智能化提升至全新高度 (macOS 15 ISO、IPSW、PKG 下载) iPhone 镜像、Safari 浏览器重大更新、备受瞩目的游戏和 Apple Intelligence 等众多全新功能令 Mac 使用体验再升级 请访问原文链接&#xff1a;https://sysin.org/blog/macOS-Sequoia/&a…

【动态规划】| 路径问题之最小路径和 力扣64

&#x1f397;️ 主页&#xff1a;小夜时雨 &#x1f397;️专栏&#xff1a;动态规划 &#x1f397;️如何活着&#xff0c;是我找寻的方向 目录 1. 题目解析2. 代码 1. 题目解析 题目链接: https://leetcode.cn/problems/minimum-path-sum/description/ 这道题目和之前一道…

基于C#开发web网页管理系统模板流程-参数传递

点击返回目录-> 基于C#开发web网页管理系统模板流程-总集篇-CSDN博客 前言 当用户长时间未在管理系统界面进行操作&#xff0c;或者用户密码进行了更改&#xff0c;显然用户必须重新登录以验证身份&#xff0c;如何实现这个功能呢&#xff1f; HTTP Cookie&#xff08;也叫 …