通过React调用GitHub API来更新自己的个人简介和状态
首先
我想通过调用GitHub提供的GitHub REST API和GitHub GraphQL API,
在确认REST API和GraphQL API的差异的同时,
更新我的个人简介和状态。
环境建设
我会主动进行环境搭建而不使用create-react-app(感觉会学到更多)。
$ node -v
v16.13.0
$ npm -v
8.1.0
$ mkdir github-api
$ cd github-api
$ npm init -y
$ npm i react react-dom typescript
$ npm i -D webpack-cli webpack-dev-server html-webpack-plugin babel-loader @babel/preset-env @babel/preset-react @babel/preset-typescript @types/react @types/react-dom
$ gibo dump Node macOS >> .gitignore
$ npx tsc --init
// ローカルサーバ起動
$ npx webpack serve
const path = require('path');
const HtmlWebpackPlugin = require("html-webpack-plugin");
module.exports = {
mode: "development",
entry: './src/App.tsx',
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'bundle.js'
},
resolve: {
extensions: [".js", ".ts", ".tsx"],
},
module: {
rules: [
{
test: [/\.ts$/, /\.tsx$/],
exclude: /node_modules/,
use: {
loader: 'babel-loader',
}
}
]
},
plugins: [
new HtmlWebpackPlugin({
template: path.resolve(__dirname, "src/index.html")
})
],
devServer: {
static: {
directory: path.join(__dirname, "dist"),
},
},
};
module.exports = {
presets: [
'@babel/preset-env',
'@babel/preset-react',
'@babel/preset-typescript'
],
targets: '> 1.5%, last 2 versions, not dead',
};
{
一部省略
"dependencies": {
"react": "^17.0.2",
"react-dom": "^17.0.2",
"typescript": "^4.5.2"
},
"devDependencies": {
"@babel/preset-env": "^7.16.4",
"@babel/preset-react": "^7.16.0",
"@babel/preset-typescript": "^7.16.0",
"@types/react": "^17.0.37",
"@types/react-dom": "^17.0.11",
"babel-loader": "^8.2.3",
"html-webpack-plugin": "^5.5.0",
"webpack-cli": "^4.9.1",
"webpack-dev-server": "^4.6.0"
}
}
{
"compilerOptions": {
"target": "es5",
"lib": [
"dom",
"dom.iterable",
"esnext"
],
"allowJs": true,
"skipLibCheck": true,
"esModuleInterop": true,
"allowSyntheticDefaultImports": true,
"strict": true,
"forceConsistentCasingInFileNames": true,
"noFallthroughCasesInSwitch": true,
"module": "esnext",
"moduleResolution": "node",
"resolveJsonModule": true,
"isolatedModules": true,
"noEmit": true,
"jsx": "react-jsx"
},
"include": [
"src"
]
}
GitHub API 摘要
使用两种类型的API来更新GitHub的个人简介和状态。

使用GitHub的REST API进行实现。
根据GitHub文档,建议指定REST API的版本。
建议通过 Accept 头明确请求此版本,否则默认情况下,所有请求将接收到 REST API 的 v3 版本,目标地址为https://api.github.com。
所以,使用fetch进行请求的代码如下:
import React, { useState, FormEvent } from "react";
export const Rest = () => {
const token = '作成した個人アクセストークン';
const [data, setData] = useState();
const [bio, setBio] = useState<string>("");
const handleSubmit = (e: FormEvent<HTMLFormElement>) => {
e.preventDefault();
fetch('https://api.github.com/user', {
method: "PATCH",
body: JSON.stringify({ bio }),
// 上記は、body: JSON.stringify({ 'bio': bio }), と等価
headers: {
Accept: "application/vnd.github.v3+json",
Authorization: `bearer ${token}`,
},
})
.then(res => res.json())
.then(setData)
.catch(console.error)
}
return (
<>
<h1>GitHub REST API で bioを更新</h1>
<form onSubmit={handleSubmit}>
<textarea onChange={e => setBio(e.target.value)} cols={50} rows={3} placeholder="your bio..." required />
<button>更新する</button>
</form>
{data && <p>{`bioを「${data["bio"]}」に更新しました。`}</p>}
</>
)
}
由于这只是一个演示,所以我们直接编写了访问令牌。但实际上,最好是将令牌写入.env文件,将该文件放置在根目录下,并使用像dotenv-webpack这样的插件,以在webpack编译时导入.env文件中写的环境变量。
(如果使用create-react-app创建了React项目,则似乎已预先安装了dotenv包,该包用于设置环境变量。)
import React from "react";
import ReactDOM from "react-dom";
import { Rest } from "./rest";
ReactDOM.render(
<React.StrictMode>
<Rest />
</React.StrictMode>,
document.getElementById('root')
);
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="utf-8">
<title>GitHub API test</title>
</head>
<body>
<div id="root" />
</body>
</html>

使用GitHub GraphQL API进行实现.
接下来,我们将使用GraphQL API来更新GitHub的状态。
似乎可以更新状态的消息和表情符号。
与REST API的不同之处,主要在于它具有一个单一的端点。
GraphQL的端点
REST API有许多端点,但GraphQL API只有一个端点。
https://api.github.com/graphql
不管所执行的操作是什么,端点始终保持不变。
我打算使用fetch来传递查询和变量给请求的body,而不使用用于React的GraphQL库等。参考以下内容。
import React, { useState, FormEvent } from "react";
export const Graphql = () => {
const token = '作成した個人アクセストークン';
const [data, setData] = useState();
const [message, setMessage] = useState<string>("");
const [emoji, setEmoji] = useState<string>("");
const handleSubmit = (e: FormEvent<HTMLFormElement>) => {
e.preventDefault();
fetch('https://api.github.com/graphql', {
method: "POST",
body: JSON.stringify({
query: `
mutation updateStatusMutation($message: String!, $emoji: String!) {
changeUserStatus(input: {message: $message, emoji: $emoji}) {
status {
message
emoji
}
}
}
`,
variables: {message, emoji}
}),
headers: {
Authorization: `bearer ${token}`,
},
})
.then(res => res.json())
.then(setData)
.catch(console.error)
};
return (
<>
<h1>GitHub GraphQL API で statusを更新</h1>
<form onSubmit={handleSubmit}>
<textarea onChange={e => setMessage(e.target.value)} cols={50} rows={2} placeholder="your status message..." required />
<input type="text" onChange={e => setEmoji(e.target.value)} placeholder="your status emoji..." required />
<button>更新する</button>
</form>
{data && <p>{`ステータスメッセージを「${data["data"]["changeUserStatus"]["status"]["message"]}」、ステータスの絵文字を「${data["data"]["changeUserStatus"]["status"]["emoji"]}」に更新しました。`}</p>}
</>
)
}
App.tsx和index.html与上面的内容相同。

概括
最终目录的结构就像这样。
$ tree -I "node_modules|README.md|.gitignore" -L 2
.
├── babel.config.js
├── dist
│ ├── bundle.js
│ └── bundle.js.LICENSE.txt
├── package-lock.json
├── package.json
├── src
│ ├── App.tsx
│ ├── graphql.tsx
│ ├── index.html
│ └── rest.tsx
├── tsconfig.json
└── webpack.config.js
顺便一提、、
<textarea onChange={e => setBio(e.target.value)} ...以下省略 />
查看这段代码,我认为每次在textarea中输入时,组件会重新渲染。
然而,当我在读React的书时,书中提到React内部有一种机制来协调重复的渲染请求,所以不必担心不必要的重新渲染。
然而,由于函数本身会在每次输入时调用,所以应该避免在此渲染函数中执行重度处理。
希望这是我个人的备忘录,如果对他人有所帮助,我会感到幸福。