初めてReactをプロダクションで採用した時に役立ったこと、情報収集について

公開日:2019 M05 4最終更新日: 2019 M11 16

React を使ったプロダクトが形になるまで、知識不足やメンタル面でぶつかったこと、解決方法などを覚書として記事にしました。新規プロダクトで使用したので過去のしがらみや技術的な負債はなく、技術選定の自由度は高い状態です。

事前に React の勉強やモックレベルのアプリは作成したものの、躓くところは多く色々困りました。極力、小さな疑問解消や当たり前過ぎると思われそうなことについても覚書として残しておきます。解説記事というよりは感想記事です。

サーバーに node.js は必要ない

React での開発時はローカル環境に node.js のインストールが必要になります(なくてもできる!という意見はあると思いますが、現状そうするメリットはないと思いますので”必要”としています)。これは npm や webpack など各種ツールをローカル開発で使い効率よく開発するためです。

あくまで開発に node.js を使用しているだけで出来上がったファイルの動作に node.js は必要ありません。ビルドした時に作成される javascript はブラウザで動く javascript ファイルです。そのため、サーバー側に node.js は必要ありません。普通の javascript や jQuery が動いているなら同じ環境で動きます。もし動いていないなら、それはパスが間違っているからかもしれません

html と javascript さえ動けば良いので普通のレンタルサーバーでも動きます。プロダクション環境に必要なのは build したファイルのみで、開発時に使用している jsxやpackage.jsonといった ファイルは必要ありません。

パッケージマネージャー

npm と yarn の選択肢がありどちらを使っても問題ありません。npmは古いバージョンの時に速度面で yarn と比較して遅いというデメリットがありましたが、現在では速度改善されているらしくyarn と遜色ないという人もいます。yarn には 固有の機能としてworkspace という機能があります。

他の人が npm 使っているプロジェクトなら npm、特に決まっていないならわたしは yarn を使います。どちらを使っても package.json は同じなので使っている人が多い方に合わせるのが良いのではと思います。

React の選択肢

自身で設定を作り開発を勧めていくのもひとつの手段ですが、JS関連の知識を持った人がいないと茨の道です。まずは設定段階でつまづき難いスターターやライブラリの使用をお薦めします。

大きな選定基準として SEO が必要かどうかをまず検討します。SEO が必要なら、静的ファイルを生成する Gatsby や、サーバーサイドレンダリングを可能にする Next.js が候補になります。

  • Next.js
  • Gatsby

更新頻度が高い、例えばニュースサイトのようなものなら Next.js 、それほど更新頻度が高くない通常の Web サイトやブログサイト、データベースを使用しないがある程度の更新性をもたせたいなら Gatsby を候補に入れてみると良いと思います。Next.jsでのサーバーサイドレンダリングはバックエンドにnode.jsなどJavaScriptが動く環境が必要なはずですので注意が必要です。

SEO が必要ないかそれほど重要ではなく、SPA で問題ないなら CreateReactApp をベースにして React 開発を行いましょうß。

SPA と SEO

Google のクローラーが最新の chrome になり、SPA 環境でも Google では SEO の問題は解決されているという状況です。しかし、通常の静的サイトと同じタイミングでインデックスされるかどうか、Google 以外の検索エンジンはどうかが分かりません。

なので、高い更新性と SEO の強さを求められるなら SPA の採用がベストではなく、現状はサーバーサイドレンダリングするか Gatsby のような静的なファイルを生成する方式をとる方が安全なはずです。SEO の専門ではないので断定はできませんが、SPA での SEO を完全に信頼するのはまだ速いという印象です。

ベースに CreateReactApp を使う

自身のプロジェクトでは SEO が必要なかったのでベースは CreateReactApp で作成しました。TypeScript や storybook など人気ライブラリと簡単に連携可能。開発環境について考える手間が大きく減ります。

build 設定など変更する時は eject せずにreact-app-rewiredを使い変更しました。

Typescript 採用

勢いのある JavaScript のスーパーセット。最初とても難しく感じますが、型がわからないところはとりあえず anyで使っても十分恩恵があり、使っているうちに any は減ってきます。変数を扱う時にでる型情報を元にしたヒント、将来的に API とやりとりするが、すぐには用意できない時のモック作成など、型情報に助けられる部分は大きかったです。

現状気になっているのは、ファイル数の増加とともにリロード時の読み込みやエラーの表示に時間がかかるようになりました。これは設定で解消できるのか、PC の性能なのか分かりません。

import SampleLibrary from 'sample-library'; // 型情報求められる
const SampleLibrary = require('sample-library'); //求められない

ライブラリ使用するかの検討で、モックレベルでライブラリを試すことがあると思います。その時に@types に型がない場合は import ではなく require でまず試すとスムーズでした。型のことは実際に使うことになってから考えます。

TypeScript はどうしてもコード量が増えてしまうものの、それ以上のメリットはありました。

storybook は難しかった

開発初期はとても気に入っていましたが、Redux の導入やデータ構造をちょっと変更したりするときのエラーで開発の手が止まりやすくなり、コメントアウトが増え、面倒になって放置される component が増えていきました。storybook を作るコストとそのメリットが、実開発に与えるメリットを超えていないと判断して今回の開発では途中で外しました。

React, Redux に翻弄される日々

Redux は React を使う上で非常に便利なライブラリであり、非常に頭を悩ませるライブラリでもあります。というのも、みんな使ってるからという理由で採用されることが増えた結果、「採用の前に、Redux が必要かをまず冷静に考えよう!」という注意書きが生まれるくらいで、Redux 不要論を唱える人もいます。また、React に hooks が正式導入されたことでまた混乱がありました。

Redux の導入にはかなり悩み、色々な記事や公式を読み直しました。

Dan Abramov 氏の解説記事で React 自体の理解も深めつつ、Redux 公式の Motivation と Core Concepts、Basic Tutorial をなんども読みました。Redux の動画もあります

Getting Started with Redux

検討を続けても Redux のふわつきは大きくなる一方で悩みがちな日々となりました。悩ぶ度、Redux 公式の Basic Tutorial をなぞりました。

情報を日々集めるていると、自分以外もReact や Redux に混乱している人は多いと感じるようになりました。本質的に正解かも分からない多くの React, Redux 記事に翻弄されるのは良くないので、信頼できる情報源を絞り込むのが重要だと考えました。ということで、色々なところから情報を集めるのをやめて、React や Redux 公式、そしてそのメンテナ達が流してくれる情報だけをまず信頼しようと。

情報の集め方

公式のドキュメントは最重要です。これはどこにでも書いてあることですが実践するのはとても難しく油断するとすぐに読まなくなります。難しい...Qiita の方がわかりやすい気がする、目的の情報に辿り着けない、などなど公式を読み続ける精神的なハードルは高めです。

しかし、結果的には色々と探し続けた結果、公式に書いてあった・・・ということが多かったです。また、React, Redux 公式の他に、下記の人の情報は信頼して追いかけていました。

Dan Abramov 氏は React チームの1人で質が高く分かりやすい情報を積極的に流してくれます。React の情報を追いかける時外すことはできません。

Mark Erikson 氏は Redux のメンテナで、やはり質の高い解説を色々な場所で流し込んでくれます。github issue でのドキュメント整備関連でも積極的に活動されているため、まだドキュメントが少ない Redux + React hooksの方向性をみたいときに特に助かりました。

Kent C.Dodds 氏は主にテスト関連で情報を多く出してくれます。テスト以外でも React の使い方を色々と解説されているので参考になります。

他にも素晴らしい情報を出してくれている人はたくさんいるとは思いますが、情報過多になるといけないのでまずは上記3人に絞り込みました。信頼する情報をベースにして他の情報を読むと混乱は小さくなります。これら以外は絶対に信じない!ということではありません。stackoverflowは普通に使います。

折り合いをつける

質の高い情報をたくさん仕入れたらベストなコードを書けるかといえば書けません。逆に、良いものに触れ過ぎて自分のコードに悲観してしまったり、多すぎるリファクタリング、思い悩んで手が止まる原因になることもありました

この対策は、今の実力を認めて期日内に必要な機能をどうすれば実装できるかを考えてコード書くしかありません。もっとも重要なのは必要な機能を期日までに実装して製品にすることです、ベストプラクティスから外れていたとしても正しく動くならひとまず良しです。少なくとも公式をなぞっていれば大きく道を外れていることはないはずで、その自信を作るためにも公式ドキュメントを読み、信頼できる情報ソースを持っておくのは大切だと思います。

また、解決が難しく、動いてはいるが後々問題が出るのでは?と感じる箇所は出てきます。それらは隠さずに issue でもプロジェクト管理系の何かでも良いので社内に情報を共有。将来経緯を追いかけやすく、誰かが解決策を持っているかもしれません。

フロントエンドは本当に色々な手法が日々出てくるので、ベストを追い求めるには相当な知識と経験が必要だと感じました。CreateReactApp も最初のページが class から hooks 使ったものになりました。hooks のベストプラクティスが確立されるに連れて周辺のベストプラクティスもまた変わっていきます。

Redux 導入

上記を経て 最終的に Redux 導入しました。どうしても結論ありきなところは否めませんが、色々試作している過程で以下の状況で大きなメリットを感じました。

  • データの加工が多い
  • データ構造が複雑になりがち
  • データの反映、保存、破棄操作がある

例えば、データを画面上で加工して保存する処理があるとします。Redux を使わない場合、データを加工するロジック、データを保存するロジックを親のコンポネントで定義し、それを props で子のコンポネントに渡します。この段階だと問題ありません。後々、保存したときに画面の右下にお知らせがポップアップする、失敗したときに別のポップアップが発生する、別画面で共通するデータの一部が保存されるといった機能など、後付の改良で親子関係が苦しくなるケースがありました。

UI の親子関係とデータ関連のロジックを Redux で分離できるとそれぞれ独立して機能を付与できるので親子関係に悩まされにくくなります。特に、React hooks 対応後の React-Redux なら従来の mapStateToProps や mapDispatchToProps を作らずに直接 import して Redux 管理のデータの読み込み、アクションの dispatch が可能です。これはとにかく便利でした。

import React from "react";
import { useDispatch, useSelector } from "react-redux";

const Sample = () => {
  const dispatch = useDispatch();
  const sampleState = useSelector(state => state.sample);

  // 省略
};

hooks の動向とベストプラクティスの充実次第では Redux なしの方が良くなる可能性はありますが、現状はあった方が便利で後々の改良にも見通しが良かったです。

また、redux-devtools を導入することで

  • データ操作の失敗がわかりやすい
  • 想定したタイミングで正しい回数 API 叩けているかを確認しやすい
  • 想定外の action が起きていないかわかる
  • 不具合時の状況再現がしやすい

など、データ操作や意図した操作をきっちり行えているか確かめるのに重宝しました。問題が起きたとき、問題が表示ロジックにあるのか、データ操作にあるのかを切り分けやすく、不具合を起こした時の state を読み込めば同じ状況を再現できます。検証中はローカルにエラー時の state を json に保存して読み込む形にしていました。

jsは非同期で動くため、想定外の小さな動きを見逃しがちになり、そんな時に目視でイベントの流れを追えるのはとても便利でした

Redux のフォルダ構成

通常の action,reducer などでフォルダきるパターンや、一箇所に集める duck パターン、それを改良した re-duck など色々な方式があります。今回は TypeScript 導入していたので公式の下記プロジェクトの構成を参考にしました。

Usage with TypeScript

このフォルダの切り方で引っかかっているのは、action と reducer が 1 対 1 になりやすく、共通の action が書きにくいということでした。1 つの action で複数の reducer 動かす時に action をどこに置くかが難しく、結局雰囲気で一番わかりやすそうなところの action に書くことにしましたが明確にルール化できてない部分です。このあたりは勉強が必要な課題になりました。

ライブラリの選定

自分で作るか、ライブラリを使うかは悩ましい問題です。React, Redux 以外のものは以下の基準で選びました

  • ライブラリの枠組みが大きすぎないこと(学習コスト高めのものは極力避ける)
  • 企業が保守あるいは使用しているなど長期的に保守される可能性が高いもの
  • release や update が 1 年以内にどれくらいされているか、issue や pull request が停滞していないか

star の数は重要な指標ではありますが公開日が古いほど有利な要素でもあります。star 数だけでなく、React の進化についていけているかも重要な要素です。react-motion よりは react-spring といった感じです。また、メインのロジックに絡む部分は可能なら極力ライブラリを使わないようにしました。

バックエンドとの連携

API 先が準備できていない時や設計中の時は 返答 される(はず)の json を用意してローカルから読み込みました。また、開発とビルド後の切り分けには NODE_ENV が便利です。

process.env.NODE_ENV === "development";

開発中だけバックエンドとドメインが違うため必要な CORS 対応や、不具合起こしたデータのデバッグで毎回 API 叩きたくない時など。

バックエンド側でデータ整形しないなら、Redux の state をそのままデータベースに保存してしまうのもお手軽で便利でした。データベースが JSON 型対応していればそこに入れてしまいます。状況の再現がとても簡単で作成に時間がかかりません。SQL で扱いにくいので全部は厳しいですがフロントメインのデータなら良さそうです。

バックエンドとやり取りする時は IE や Edge の対応に注意が必要です。これらブラウザは polyfill が必要になります。CreateReactApp なら独自の polyfil がありますのでそちらをまずは検討します。

など。ただ、polyfilは最終のビルドファイルのサイズに大きく影響を与えるので、とりあえず読み込んでおくという考えは微妙です。安全ではありますが。

build した先が相対パスかどうか

開発がひと段落して yarn build などした後。設置場所によってはファイルの読み込みを相対パスにしたいことがあります。その時は package.json に homepage を追加します

  "version": "0.1.0",
  "homepage": ".",

サーバー側で生成した動的な URL からの相対パスにする時は、サーバーに設置して build 内の index.html 該当部分を直接書き換えるしかないと思います。

サーバーのgzip対応

buildするとターミナルにビルドファイルのサイズが表示されますが、実際に出力されたファイルはそれよりもかなり大きいファイルサイズのはずです。表示されたサイズは、サーバーからgzipという圧縮形式で配信された時のサイズを想定しています。

gzipはサーバー側の設定が必要なのでフロントエンドではどうこうできません。実際に設置してみてResponse Headersに

content-encoding: gzip

となっていれば読み込みサイズがbuild時に表示されたものと同じになっているはずです。SSL環境は必須。圧縮配信されないとReactのプロジェクトは厳しいのでサーバー設定は忘れずに。一番初期のHello worldでも130kbくらいあります、gzipで40kbくらい。これよりも容量を下げるならpreactなどより軽量なライブラリを使うことになります。

開発がひと段落しての感想

初の React 案件での開発は色々な迷い、プレッシャーがありました。保守の段階や新たな要望が増えればまた葛藤も出てくると思います。

ただ、開発自体はとても楽しく、数ヶ月集中して React 触れたのでフロント開発の実力を伸びすこともできたと実感しています。今回は React hooks 正式実装後だったので、class 使わずに全て function で作成しました。hooks の情報が増えるにつれてもっと開発が楽しくなりそうなので、継続して React 触っていきたいというところです。フロントエンド楽しい


JavaScript
hidekazoo
作者: hidekazooTwitter
JavaScriptやPHPなどプログラム関係やDockerといった開発環境など、ITエンジニアとして興味あることを紹介しているサイトです