本文基于howtographql教程,使用下面较为容易上手的技术栈,为大家做一个极简入门
- 前端
- react@18.2.0(基于create-react-app@5.0.1版本创建项目)
- react-router-dom@6.8.0
- urql@3.0.3
- graphql@16.6.0
- 后端
- graphql-yoga@3.5.1
- @prisma/client@4.9.0
- graphql@16.6.0
由于不知道你看到本文时,相关技术库的版本迭代到了多少,因此列出本文内使用的相关包版本号,如果遇到不可知的问题,可以与上面的版本号保持一致。(成文于2023-02-03)
本文是该系列的第一篇,为大家初步搭建前后端,以及生成一个hello world的demo。
graphql极简入门教程目录:
- 第一篇:基于react和graphql-yoga搭建前后端,并实现一个hello world
- 第二篇:基于prisma及sqlite,通过playground创建及查询数据
- 第三篇:在react中执行graphql的新增和查询操作
- 第四篇:react添加路由导航、前后端搜索功能
- 第五篇:添加分页及排序功能
- 第六篇:后端编写用户登录及注册功能
- 第七篇:前端对接用户系统
- 第八篇:前后端接入github的Oauth系统
- 第九篇:graphql实时订阅
项目准备
创建react项目
在命令行中基于create-react-app快速创建react项目:
npx create-react-app hackernews-react-graphql-yoga
打开刚刚创建的项目,在src目录下新建components及styles文件夹,并将App.tsx及App.test.tsx移动到src/components文件夹下,index.css及App.css移动到src/styles文件夹下,调整后的目录结构如下:
├── README.md
├── package-lock.json
├── package.json
├── public
└── src
├── components
│ ├── App.js
│ └── App.test.js
├── index.js
├── logo.svg
├── reportWebVitals.js
├── setupTests.js
└── styles
├── App.css
└── index.css
打开src/index.tsx文件,将文件内的代码替换为(主要是修改一下文件的路径):
import React from 'react';
import ReactDOM from 'react-dom/client';
import './styles/index.css';
import App from './components/App';
import reportWebVitals from './reportWebVitals';
const root = ReactDOM.createRoot(
document.getElementById('root') as HTMLElement
);
root.render(
<React.StrictMode>
<App />
</React.StrictMode>
);
// If you want to start measuring performance in your app, pass a function
// to log results (for example: reportWebVitals(console.log))
// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
reportWebVitals();
由于本文着重于讲述如何使用graph搭建服务,为了加速开发速度,这里引入一个css库tachyons
打开public/index.html,添加tachyons:
<link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" />
<!--
manifest.json provides metadata used when your web app is installed on a
user's mobile device or desktop. See https://developers.google.com/web/fundamentals/web-app-manifest/
-->
<link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
<!--
Notice the use of %PUBLIC_URL% in the tags above.
It will be replaced with the URL of the `public` folder during the build.
Only files inside the `public` folder can be referenced from the HTML.
Unlike "/favicon.ico" or "favicon.ico", "%PUBLIC_URL%/favicon.ico" will
work correctly both with client-side routing and a non-root public URL.
Learn how to configure a non-root public URL by running `npm run build`.
-->
+ <link
+ rel="stylesheet"
+ href="https://unpkg.com/tachyons@4.12.0/css/tachyons.min.css"
+ />
接着打开src/styles/index.css文件,将文件内样式替换为
body {
margin: 0;
padding: 0;
font-family: Verdana, Geneva, sans-serif;
}
input {
max-width: 500px;
}
.gray {
color: #828282;
}
.orange {
background-color: #ff6600;
}
.background-gray {
background-color: rgb(246, 246, 239);
}
.f11 {
font-size: 11px;
}
.w85 {
width: 85%;
}
.button {
font-family: monospace;
font-size: 10pt;
color: black;
background-color: buttonface;
text-align: center;
padding: 2px 6px 3px;
border-width: 2px;
border-style: outset;
border-color: buttonface;
cursor: pointer;
max-width: 250px;
}
到这里我们已经搭建起了一个简单的前端页面,接下来我们创建后端服务。
基于graphql-yoga创建后端服务
在命令行中,键入以下指令安装graphql-yoga
npm install graphql graphql-yoga
并安装nodemon(检测到文件变更,自动重启服务)
npm install nodemon --save-dev
让我们创建一个server目录来存放后端的内容,并添加一个index.js文件,在文件中增加如下的内容:
// 路径:src/server/index.js
import { createServer } from 'node:http'
import { createYoga } from 'graphql-yoga'
import { createSchema } from 'graphql-yoga'
const schema = createSchema({
// ①
typeDefs: `
//②
type Query {
// ③
hello: String!
}
`,
// ④
resolvers: {
Query: {
hello: () => 'world'
}
}
})
// 基于graphql的scheme,创建一个graphql-yoga的实例
const yoga = createYoga({ schema })
// 基于实例化后的yoga,创建一个server
const server = createServer(yoga)
// 后端将在http://localhost:4000/graphql地址上启动server
server.listen(4000, () => {
console.info('Server is running on http://localhost:4000/graphql')
})
①中typeDefs字段传入的内容,定义了GraphQL Schema(笔者保持与官方英文名称,暂不翻译)。它其实就像你在写typescript时,会预先定义类型一样。
示例中的内容含义是:②是一个查询类型,③有一个叫做hello的字段,这个字段是一个string类型,!代表这个类型一定会返回一个不为null的字符串。
④中的resolvers是针对GraphQL Schema的数据定义,具体执行相关的方法,返回与GraphQL Schema定义数据类型一致的数据
用上面的代码举例就是:我之前定义了一个查询类型会返回一个不为null的hello字段,他是字符串类型,但这个只是我对于数据类型的定义,具体怎么获取这个数据,就需要通过resolvers里的设定来实现。
如果还是不太明白,可以结合下面的具体的返回数据来理解。
请注意观察
resolvers.Query中的结构与typeDefs中的type Query定义结构之间相同的地方。
在package.json文件内添加:
{
...,
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test",
"eject": "react-scripts eject",
+ "start:server": "nodemon --exec node src/server/index.js"
},
...
}
在项目根目录下,执行下面命令
npm run start:server
并在浏览器中打开:http://localhost:4000/graphql,进入play ground页面
在左侧的输入框,输入下面的内容:
query {
hello
}
执行后我们可以看到,返回的结果与我们在resolvers中定义的一致
安装urql
urql是我们在react中请求graphql服务的工具,类似于axios
在项目根目录下,键入以下指令,安装urql
npm install --save urql
下面我们在react中引入urql,将src/index.js的内容替换为:
import React from 'react';
import ReactDOM from 'react-dom/client';
import './styles/index.css';
import App from './components/App';
import reportWebVitals from './reportWebVitals';
import { createClient, Provider } from 'urql';
// ①
const client = createClient({
url: 'http://localhost:4000/graphql',
});
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
<React.StrictMode>
{/*②*/}
<Provider value={client}>
<App />
</Provider>
</React.StrictMode>
);
// If you want to start measuring performance in your app, pass a function
// to log results (for example: reportWebVitals(console.log))
// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
reportWebVitals();
①中我们创建了一个客户端,graphql服务端的地址设置为http://localhost:4000/graphql
②中我们提供了一个上下文,供组件内使用
完成hello world
接下来将src/components/App.js的内容替换为:
import React from 'react';
import { useQuery } from "urql";
// ①
const HelloQuery = `
query {
hello
}
`;
function App() {
// ②
const [result] = useQuery({
query: HelloQuery,
});
// ③
const { data, fetching, error } = result;
// ④
if (fetching) return <p>Loading...</p>;
// ⑤
if (error) return <p>Oh no... {error.message}</p>;
// ⑥
return (
<span>{JSON.stringify(data)}</span>
);
}
export default App;
①中,我们定义了查询的内容,与之前我们在play ground里输入的一致
②中我们在useQuery的hook中,传入定义好的查询内容,解构出result结果
③由于result中包含
data:返回的数据fetching:当前是否正在从后端获取数据中error:错误信息
因此需要解构后,方便后续使用
④如果fetching为true,意味着当前正在获取数据中,此时展示loading文案
⑤如果请求失败,展示错误信息
⑥展示返回的数据
启动react服务
npm run start
打开 http://localhost:3000 后你在页面会看到下面的数据:
对比一下之前在play ground返回的数据,两个的内容是一致的
恭喜!你已经成功完成了最经典的hello world入门!接下来我们将会一步步搭建一个hackernews的简化版前后端程序。
开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 1 天,点击查看活动详情