3 時間で React 入門 ~ GraphQL と Relay で作る Web アプリケーション~|研修コースに参加してみた
今回参加したコースは 3 時間で React 入門 ~ GraphQL と Relay で作る Web アプリケーション です。
今やモダンなフロントエンドの開発ではスタンダードとなった React を、さらに欲張りに GraphQL を使って API サーバからデータを取得して表示する簡単な Web アプリケーションを書いてみました。
こう書くとモダンな香りがプンプンして、「わたしにはちょっと早いかな」と気後れしてしまいそうです…
が、しかし!
Hello World からテンポよく進められ、たった 3 時間で React の良さやコンポーネントの粒度などお作法がわかりました(それだけ React のエコシステムが充実しているという証でもありますが)! モダンなフロントエンド開発に入門したい方にはとってもオススメのコースでした!!
では、どのようなコースだったのかレポートします!
もくじ
コース情報
想定している受講者 |
|
---|---|
受講目標 |
|
講師紹介
モダンな技術にも対応できる講師と言えば、米山 学 さんです。
Java はもちろん Python / PHP などスクリプト言語、 Vue / React など JavaScript だってなんだってテックが大好き。原点をおさえた実践演習で人気
React と並ぶモダンフロントエンドフレームワークの Vue.js のコースでも登壇いただいています。
React とは
まずは React の説明ですが、これはいろいろなところで紹介されているので簡単に。
- 3 大フロントエンドフレームワークの一つ
- Angular / Vue
- コンポーネントベース (部品) で UI を構築
Hello, React
まずは JSX で書くのではなく、わかりやすく HTML で Hello World ならぬ Hello React を書いてみます。
- HTML を書く
<!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <title>Hello React</title> </head> <body> </body> </html>
- script タグで必要なライブラリを指定
- 今回は開発用の development を使う
- 本番リリースのときは production を使う
<head> <meta charset="utf-8" /> <title>Hello React</title> <script crossorigin src="https://unpkg.com/react@17/umd/react.development.js"></script> <script crossorigin src="https://unpkg.com/react-dom@17/umd/react-dom.development.js"></script> </head>
- DOM を指定
<body> <div id="root" /></div> </body>
- JavaScript を書く
<div id="root" /> <script> const element = React.createElement('h1', [], 'Hello React!'); // createElement で要素を作成 ReactDOM.render( // render は書き出す。第1引数は対象となるオブジェクト。第2引数は対象となる要素を取得 element, document.getElementById('root') ); </script> </div>
VSCode では Alt + B で実行できるので、やってみます。
JSX で書く
JSX とは、 JavaScript ですべて完結させるために HTML を表現する記述方式で、 React では HTML ではなく JSX を使います。
- JSX は JavaScript ではないので、 Babel というコンパイラ(トランスコンパイル)で JavaScript に変換する
<head> <script src="https://unpkg.com/@babel/standalone/babel.min.js"></script> </head>
<script type="text/babel"></script>
- JSX で書く
<script type="text/babel"> const element = <h1>Hello React!</h1>; // <h1>..</h1> は JSX ReactDOM.render( element, document.getElementById('root') ); </script>
- JSX の書き方の注意
- 単一要素しか render できない
- NG
<h1>...</h1> <h2>...</h2>
- OK
<div> <h1>...</h1> <h2>...</h2> </div>
- NG
- 単一要素しか render できない
- JSX の書き方の注意
これだけ見ると、 HTML も JSX もそれほど変わりはありませんね。
React コンポーネント
React は UI をコンポーネントという部品で構成します。例えば、 ボタンやアイコンなどの細かな部品を作り共通化、そこからさらにヘッダーのような大きな部品にして、ページ全体を作ります。
と説明を伺いながら、個人的にはコンポーネントの粒度が難しいなと感じてました。ちなみに、素人考えですが、データの更新があるかないかで切り分けすると良さそうに思いますが、何かベターなやり方はあるんでしょうかねぇ。
と主観はさておき、コンポーネントとはどのようなものか解説いただきました。
- 関数コンポーネント
- 関数であって、状態は保持しない
- 副作用がない
- React Hooks という API が追加されたため、これだけを使うのが主流
- クラスコンポーネント
- 状態を保持する
- 副作用がある
- 現在は使わなくなっている
ここでも関数型言語っぽい、単一方向のデータの流れが見えますね。やはりオブジェクト指向ではない考え方が普及していると感じます。
これもさておき、実際にコンポーネントを作成してみます。
- React Hooks を使った関数コンポーネントを作成
- JavaScript で関数を書く
- 必ず return で JSX を返すこと
- まずは Hook を使わないで書く (カウントしないボタンになる)
function Counter() { let count = 0; // 初期化してしまうのでカウントアップせず 0 のまま return ( <div> <p>You clicked {count} times</p> <button onClick={() => ++count}>Click me</button> </div> ); }
- State Hook を使う
function Counter() { const [count, setCount] = React.useState(0); // useState が Hook。引数は現在の値と、更新した関数コンポーネントの2つが必要 return ( <div> <p>You clicked {count} times</p> <button onClick={() => setCount(count + 1)}> Click me </button> </div> ); }
実際に動かしてみます。
Create-react-app を使ってみる
React の初歩的な使い方がわかったところで、現場での使い方に進みます。
- これまでのように生で書くことはなく、いまはスケルトンとして用意されている Create-react-app を使う
- webpack や babel, ESlint などが同梱されている
これはいちいち考えなくてよいので、便利ですね。
ビルドする
- インストールには npx を使用する
- npm パッケージのバイナリを実行する(めっちゃいい!高速!!)
$ npx create-react-app my-app
インストールの結果、このような構成になりました。
続いて、ビルドします。
- CSS を Javascript から読み込んでレンダリングする
- テスト用の Web サーバも実行される
$ npm start # yarn もあるが、今回は npm を使う
便利すぎまする!!
このあと、 app.js を Hello World に変更し、必要のないライブラリを削除しました。
Web アプリケーションを開発しよう
続いて、いよいよ Web アプリケーションの開発を進めていきます。
- お題: 書籍データを表示するページを作成する
- コンポーネントでわける
- 今回の場合は テーブル と 行 でファイルをわける
テーブル と 行 に分ける感覚が新鮮でした。やはりデータ更新する単位でコンポーネントを分けたほうが良さそうです。
では、実際にベースとなる テーブル と 行 のコンポーネントを書きます(まずは書籍データを静的に書く)。
ここから直に書いていた書籍データを変数にします。
-
関数の引数に props で指定する
codeBooksRow.jsfunction BooksRow(props) { return ( <tr> <td>{props.isbn}</td> <td>{props.title}</td> </tr> ); } export default BooksRow;
codeBooksTable.jsimport BooksRow from './BooksRow' function BooksTable() { return ( <table> <thead> <tr> <th>ISBN</th> <th>TITLE</th> </tr> </thead> <tbody> <BooksRow isbn='001' title='Sample' /> </tbody> </table> ); } export default BooksTable;
- データを投入する
- この時点では書籍のダミーデータを定数で定義
- 親コンポーネントから投入する
codeBooksTable.jsimport BooksRow from './BooksRow' function BooksTable() { const rows = [ <BooksRow isbn='001' title='SampleA' />, <BooksRow isbn='002' title='SampleB' />, <BooksRow isbn='003' title='SampleC' /> ]; return ( <table> <thead> <tr> <th>ISBN</th> <th>TITLE</th> </tr> </thead> <tbody> {rows} </tbody> </table> ); } export default BooksTable;
ブラウザで確認すると、無事に表示されていました!
GraphQL でデータ投入する
続いて、定数でデータを書いたところを変えて API サーバから投入します。
WebAPI とは
まずは WebAPI について説明いただいたのですが、以前のコースでも紹介していますので、ここでは割愛します。
GraphQL とは
- Facebook が開発
- REST API の様々な欠点を解決
- 厳密にリソースを指定できる (今回のお題では isbn や title )
- クエリが作れる
- 今までは様々な REST API を叩いて取得していた
- 通信パフォーマンスが良くなる
- 厳密にリソースを指定できる (今回のお題では isbn や title )
従来の REST API では必要不要構わず、リクエストに対してガバっと丸ごとのデータを JSON で返されることが多く、フロントエンドでパースして必要なデータを抽出・整形して表示する必要がありました。
なお、 GraphQL は GitHub の API として採用されたことで一躍有名になりました。
GraphQL の API サーバを立てる
GraphQL のインストールから API サーバを立てるまでの手順です。
- react-app 配下に server ディレクトリを作成
- Node.js の Express という Web アプリケーションフレームワークを使う
- npm で、そのほか必要なパッケージをインストール
実際にサンプルをやっていきます。
- 必要なパッケージを npm でインストール
$ npm init -y $ npm install express graphql express-graphql cors
- GraphQL API サーバを作成 hello-gql.js
- スキーマ(データの定義)とクエリの種類を定義します
const app = require('express')(); const {graphqlHTTP} = require('express-graphql'); const {buildSchema} = require('graphql'); const cors = require('cors'); const greetingSchema = buildSchema(` type Query { message: String } `); app.use(cors()); app.use('/graphql', graphqlHTTP({ schema: greetingSchema, rootValue: {message: 'Hello GraphQL!' }, graphiql: true })); app.listen(4000, () => console.log('GraphQL Server is running on localhost:4000/graphql'));
- 7 行目: GraphQL のクエリには Query と Mutation がある
- 今回は Query を使う( SQL でいう SELECT )
- Mutation は SQL でいう INSERT, UPDATE, DELETE
- message という key で string 型という定義をしている
- 12 行目: cors というライブラリを使っている。これで異なるドメインのサーバでもアクセスでき HTTP リクエストを飛ばせる
- 15 行目: データを投入
- graphql サーバを起動
$ node .\hello-gql.js GraphQL Server is running on localhost:4000/graphql
起動したので http://localhost:4000/graphql
にアクセスしてみます。
おお~!やりました!!
また、 GraphiQL と呼ばれるブラウザで使える GUI 開発環境が立ち上がっていますので、試しにクエリを叩いてみます!
パラメータでデータを取得できる API サーバを作成
続いて、サンプルではなく今回のアプリケーション用に書籍データを入れた GraphQL API サーバを立てます。
- books-api.js を作成
const app = require('express')(); const {graphqlHTTP} = require('express-graphql'); const {buildSchema} = require('graphql'); const cors = require('cors'); const bookSchema = buildSchema(` type Query { Book(isbn: String!): Book Books(title: String): [Book] }, type Book { isbn: String title: String authors: [String] price: Float } `); const books = [ { isbn: '978-111', title: 'Web API Design Handbook', authors: ['George Reese', 'Christian Reilly'], price: 4.99 }, { isbn: '978-222', title: 'React Programming Basics', authors: ['Eric Freeman', 'Elisabeth Robson'], price: 38.97 }, { isbn: '978-333', title: 'GraphQL in Depth', authors: ['Matthias Biehl'], price: 9.99 } ] const BookQuery = args => { const isbn = args.isbn; return books.filter(Book => Book.isbn === isbn)[0]; } const BooksQuery = args => { if (args.title) { const title = args.title; return books.filter(Book => Book.title.match(new RegExp(title))); } return books; } app.use(cors()); app.use('/books', graphqlHTTP({ schema: bookSchema, rootValue: { Book: BookQuery, Books: BooksQuery }, graphiql: true })); app.listen(4000, () => console.log('GraphQL Server is running on localhost:4000/books'));
!
はクエリを投げるときに必須の key であることを示すtype Query { Book(isbn: String!): Book Books(title: String): [Book] },
- サーバを起動
$ node books-api.js
実際に GUI の GraphiQL でクエリを投げて、レスポンスを取得してみます。
- ISBN から Book を問い合わせるリクエスト
{ Book(isbn: "978-111") { title authors price } }
- 結果
- 結果
- Books (全件表示)のリクエスト
{ Books { title price } }
- 結果
- 結果
- 実際には直接クエリを書かずに、 query 関数を使って動的に処理する
query getBook($isbn: String!) { Book(isbn: $isbn) { title authors price } }
- 結果
- 結果
さすがに SQL のようなクエリは書けませんが、パーサを書いて目的のデータを取得するより、はるかに直感的で楽ですね!
フロントエンドと GraphQL を連携する
最終段階として書籍データを表示するフロントエンドと GraphQL サーバを繋ぎます。
- 副作用処理と呼ばれる
- React Hooks の useEffect() を使う
- データを取得するために JavaScript の async / await と FetchAPI を使う
では、やっていきます。
- データを取得する fetchGraphQL.js を作成
async function fetchGraphQL(gqlQuery, params) { const response = await fetch('http://localhost:4000/books', { method: 'POST', headers: { 'Content-Type': 'application/json', 'Accept': 'application/json', }, body: JSON.stringify({ query: gqlQuery, variables: params }) }); return await response.json(); } export default fetchGraphQL;
- BooksTable.js のデータ取得と表示部分を変更
import React, {useState, useEffect} from 'react'; import fetchGraphQL from './fetchGraphQL'; import BooksRow from './BooksRow'; function BooksTable() { const [books, setBooks] = useState([]); const query = `query getBooks($title: String!) { Books(title: $title) { isbn title } }`; useEffect(() => { fetchGraphQL(query, { title: 'a' }) .then(response => { setBooks(response.data.Books); }).catch(error => { console.error(error); }); }); const rows = []; books.forEach(book => { rows.push( <BooksRow isbn={book.isbn} title={book.title} key={book.isbn} /> ); }); return ( <table> <thead> <tr> <th>ISBN</th> <th>TITLE</th> </tr> </thead> <tbody> {rows} </tbody> </table> ); } export default BooksTable;
- useEffect() の仕様
- promise を返す
- then (正常処理)と catch (エラー処理)を書く
- useEffect() の仕様
書籍データが表示されているか確認します!
Relay を使う
今回はさらに欲張りに Relay というデータの fetch を行うライブラリを使ってみました。
- 今回のような単純なアプリケーションでは使わなくてもよいもの
- 様々なデータを取得して更新しながら、ちゃんと順番に表示されることを助ける仕組み
- 具体的にはサスペンス ( Suspense ) と呼ばれる遅延実行の仕組み
- Relay のような仕組みがないと A -> B → C と順番に表示したいところ、データ全部が揃うまで待ったり、 B が先に取得された場合、 B が先に表示されてしまう
実際にアプリケーションを書こうとすると、ここは悩むところなのですが、ページの都合上、今回はこれを割愛しました…。
「どうやるのか知りたい!」という方はぜひコースにご参加ください!
まとめ
今やモダンなフロントエンドのスタンダードとなった React を、さらに欲張りに GraphQL を使って API サーバからデータを取得して簡単なアプリケーションを書いてみました。
受講前は「モダンな技術が満載なので頑張って追いつかねば」と気負っていましたが、 Hello World からテンポよく進められ、 React の良さとコンポーネントの分け方の粒度、データ取得などがわかりました! GraphQL も触れて大満足です。
以前に Vue.js のコースに参加した際は、 JSX で書かず、今まで親しんだ HTML や CSS で書けるのでいいかなぁと思っていましたが、なかなかどうして Create-react-app や React Hooks のようなライブラリや API を使ってみるとエコシステムの発展ぶりがわかり、これは React 一択なのではと感じられました。
モダンなフロントエンド技術を身につけたいという方には、 3 時間で高速道路のように React のお作法がわかるので、とってもオススメです!!
label SEカレッジを詳しく知りたいという方はこちらから !!
IT専門の定額制研修 月額28,000円 ~/ 1社 で IT研修 制度を導入できます。
年間 670 講座をほぼ毎日開催中!!
SEプラスにしかないコンテンツや、研修サービスの運営情報を発信しています。