えいのうにっき

a-knowの日記です

「React.js & Next.js超入門」を読んで、簡単なサイトを作るところまでやってみた

React.js & Next.js超入門

React.js & Next.js超入門

勉強もかねて。このへんの技術はずっと様子見していたのだけど、さすがにそろそろ味見をしてみてもいいのかなと思ったのと、あとは純粋に興が乗ったこともあり。

実は、ひとつ前のエントリ「instax mini Link がおもしろい - えいのうにっき」で紹介したサイト( 「はじめまして」を、てのひらサイズで。 | instax mini Link ✖ Introduction )の構築・一部の動作に、Reactを使ってみている。

blog.a-know.me

もともと jQuery + Bootstrap で作られている有料テーマを購入しそれをカスタマイズしている、ということもあって、"オールReact" とはいってないんだけど。

github.com

勉強してみた結果

Reactなかなかイイじゃん、といった感想を持った。触れてみて、どうしても水が合わないと感じたらVueの方を勉強してみようかなと思っていたけど(そもそも二者択一をするようなものでもないと思うけど)、実際のところそうでもなかったので、今後作るものは極力Reactを使うようにしたいなと思う。

一方で、babel とか webpack とか、あとは「npm と yarn、どっちがいいの?」みたいなところにはこの本ではあまり触れられておらず、「こう使いましょう」というところに記述がとどまっていたので、これらについては相変わらずよくわかってないままだ。ここらへんのほうが難しいんじゃなかろうか。

あと、この本では React Hooks は扱われてないんだけど、Hooks 最高、ということだけは何人かから見聞きしているので、次につくるやつではぜひそれを試してみたいなと思っている。

以下は、本書を読みながら取った個人的なメモ。初学者向けの内容ならではの「いったんここではこういうことにしておきましょう!」的なものが、おそらく多分に含まれているのではないか?と感じている。書いてあることで何か気になる点があれば教えてください。

読書メモ

JSX

  • 文法拡張
  • JavaScriptの文法を拡張し、HTMLなどのタグを値として直接記述できるようにするもの
  • {} で変数や関数などを埋め込むことができる

Babel

  • 最新の JavaScript の仕様で書かれた JavaScript のコードを、古い仕様にコンパイルするためのもの
  • JSX の記述を JavaScript のコードに変換する際にも利用可能

JSX 注意点

  • 開始タグと終了タグに分かれていない、1つだけのタグ(inputタグなど)は必ず <xx /> と書く必要がある

コンポーネント

  • 必ず大文字で始まる名前である必要がある

コンポーネントのクラス

  • 必ず React.Componet を extends する
  • エレメントを返す render() メソッドを必ず定義する

ステート

  • コンポーネントの状態を表す値を保管するためのもの。
  • プロパティを変更した場合のその反映には ReactDOM.render を呼び出す必要があるが、ステートを使う場合にはそうした更新作業は必要なく、値を更新するだけで自動的に表示が更新される。
  • this.state = { ... } での初期化ができるのは constructor だけ
  • それ以外の場所でのステートの更新は以下のいずれかの方法でおこなう必要がある
  • setState によって、ステートの値が完全に置き換わるわけではなく、値が追加・更新されることに注意する。
    • setState は値を追加するだけで、削除はしない。

バインド

  • コンポーネントに関数を渡す – React
    • this.props や this.state のようなコンポーネントの属性に、関数がアクセスできるようにする方法。「関数にコンポーネントをバインドする」
    • render でも this にアクセスしていた。それなら this.render = this.render.bind(this); も必要なのでは?
      • React では、一般的に他のコンポーネントに 渡す メソッドしかバインドする必要はありません。たとえば、<button onClick={this.handleClick}> というコードは、this.handleClick を渡しているので、バインドする必要があります。しかし、render メソッドやライフサイクルメソッドをバインドする必要はありません。それらは他のコンポーネントに渡すことがないからです。
      • (bind しても動いた)
  • Reactの基礎を学ぶ - Qiita
    • ES6以降で、イベントハンドラ内でthis(コンポーネント)を使いたい場合、constructorかJSX内でthisをbindしないといけない。

event.preventDefault();

  • 発生したイベントを消費する。なくす。
  • フォームの送信をさせなくするなどができる。

コンテキスト

  • 各コンポーネントで共通の値をもたせることができる
  • クラスの外側で const context = React.createContext(data); する
  • クラス内で static contextType = context する
    • contextType は固定
    • this.context でアクセス可能
  • Provider
    • 一時的にコンテキストの値を変更するためのもの
    • <HogeContext.Provider value={ data }> ... </HogeContext.Provider>

Redux

  • 状態管理ユーティリティ
  • Reactで個別に扱われるさまざまなコンポーネントの状態(現在の値)を統合して管理する機能を提供する
  • 特徴
    • 値の保管場所はひとつだけ
    • 値は読み取り専用、書き換え不可
    • 値の変更は関数として用意されている
    • setState する際、参照の同じ state を渡すと、参照先の内容が変更されていても Redux としては変更なしと判断され、ストアの値も更新されない。
  • 仕組み
    • store
      • データを保管し管理するもの。ここに保管される値は state と呼ばれる
      • store の中に、state と reducer が組み込まれている形になる
      • store = createStore(reducer); で作成
    • provider
      • store を他のコンポーネントに受け渡すための仕組み
      • provider のタグ( <Provider store={store}> ... </Provider> のように記述。store= は固定)の中にコンポーネントを記述すると、その内部コンポーネントでstoreに保管されている値や処理が使えるようになる
    • reducer
      • store に保管されるステートを変更するための仕組み
      • function reducer(state = stateVar, action ) { ... } で関数として作成。内部では、最終的にステートをreturnする。「どういう action.type のときにどんな値を state として return するか」が reducer の役割。
        • stateVar は store に保管する値。初期値。
        • action は reducer が呼び出されるとき、呼び出しの内容・情報をまとめたオブジェクト。type プロパティは必ず用意される。
    • connect
      • コンポーネントに store を接続するための関数。
      • Hoge = connect(func)(Component);
        • let wrapWithConnect = connect(func); Hoge = wrapWithConnect(Component); を1行で書いたもの
      • これにより、コンポーネントの props にストアの値が組み込まれるので、 this.props.xxxx といった形で値を利用することが可能になる
      • func で指定する関数は、「このコンポーネントで利用するステートを返す」関数。func には state が引数として渡される。
        • コンポーネントに store を接続すると、コンポーネントからは this.props.xxxx で利用可能になるため、本当に必要なものだけを返すようにするのがよい。
    • dispatch
      • connect されている store の reducer を呼び出して(アクションを送信して)値を操作するための機能。
      • this.props.dispatch(action); のように使う。action には必ず type を指定する。 React本での学び
      • reducer を利用するには store が必要なので、dispatch するためには connect しておく必要がある。

Redux Persist

  • redux-persist
  • 揮発するデータをローカルストレージで管理
  • persist reducer
    • 設定情報
      • const settings = { key: keyName, storage }
    • reducer 本体
      • const hoge = persistReducer(settings, reducer)
  • persistor
    • store = createStore(persistReducer); hogePersistor = persistStore(store)
    • persist gate を利用する際に必要なほか、永続化の停止や再開、永続化済みデータの削除などをおこなう際に必要となる
  • persist gate
    • コンポーネントの表示を待たせるためのもの。なので指定しない場合でも Redux Persist の動作には影響しない。
    • <PersistGate loading={ ... } persistor={ hogePersistor } > ... </PersistGate>
  • ブラックリスト / ホワイトリスト
    • Redux Persist の永続化対象に含めるかどうかを指定できるもの
    • Persist Reducer を作るときに渡す設定情報で指定可能
    • 永続化対象のステートのフィールド名で指定

export default ...

  • そのファイルのデフォルトとして ... をエクスポートする

Next.js

  • Reactをサーバーサイドでレンダリングし表示するプログラム
  • 生成されるページを静的Webページとして作成し表示することも可能。
    • HTMLのタグとしての表示内容の出力がされる形となるので、動的なページ操作などの処理のない場合のみ。
  • 複数ページをもたせやすい
    • React は基本的にSPA向け
  • pages ディレクトリ内にページ表示のためのスクリプトファイルを配置する。
  • HTMLファイルは使わない。
  • next.config.js により Next.js の設定情報を記述する。
    • exportPathMap により出力ページのマッピングをおこなう。
  • ビルトインCSS
    • JSXに埋め込むスタイルシート情報
    • <style jsx>{\ ...(CSS記法)... `}`
    • CSSファイルをそのまま読み込んで使うことはできない。
  • 外部スタイルシートの利用
    • export default <style>{\ ... `}` としたファイルを用意する
    • 用いる側でそれをインポートし、render する jsx 内で {style} などとしておく。
  • <Head>
    • ヘッダー情報の設定をおこなうための専用のコンポーネント。
    • jsxのなかであればどこに記述しても問題ない。
  • Next.js で Redux を使う
    • AppWithRedux コンポーネントを作る
      • Reduxのストアを初期化し、それを属性に指定したAPPコンポーネント
      • ストアを作ったら、そこにinitStoreという関数を用意しエクスポートしておく。AppWithRedux コンポーネント でストアの initStore をインポートするように import 文を用意しておく。
    • 修正Appコンポーネントを作る
      • NextのAppコンポーネントを継承してカスタマイズしたAppコンポーネントを作る
    • ストアを用意する
      • ステートの初期値を用意する / reducer を定義する / createStore 関数を定義する(AppWithRedux コンポーネントから呼び出される)
      • NextでReduxを利用するためには、createStoreの第3引数に Redux Thunk のミドルウェアを指定する必要がある
        • import { createStore, applyMiddleware } from 'redux';
        • import thunkMiddleware from 'redux-thunk';
        • createStore(reducer, state, applyMiddleware(thunkMiddleware))

Redux Thunk

  • アクションの非同期実行に関する機能を提供するミドルウェア

感想

  • ReactとNext.js、そういう関係性だったのか、なるほど......?
  • データの設計と同時に、stateの設計も大事な気がする?
  • ゼロからいきなりReactのコードを書き始めるのはきっと難しくて、まずはガワとなる画面がhtmlとして作られておくとなんとかできそう
  • Next.js で、 /other への情報は next.config.js に追記しなくていいのはなぜ?

本自体の感想

  • 作りながら学びたい人(=僕)にはうってつけだと思う
  • 一点だけ難癖をつけるとすれば、ひとつ(もしくは複数)のファイルをどんどん雪だるま式につくりあげていくスタイルか?と思いきや、いきなり2つくらい前の段階のコードをベースに「それを改変してみましょう」みたいな構成になってしまっているので写経のしにくさを感じる場面が多々あった。ひとつのプロジェクトを使いまわし続けるのは、こういう本では悪手な気がする
    • 途中からgitでバージョン管理しながらやることで対処した

おわり

やはり自分には、初学者向けの本(サンプルアプリ的ななにかを作ってみることをテーマとした本)を写経して、その後ごく簡単な何かを作ってみる、というスタイルが合っている。自分にとって新しいことの勉強になり、とても楽しかった。

React.js & Next.js超入門

React.js & Next.js超入門

オマケ

実はこの本の前に Try PWA (技術の泉シリーズ(NextPublishing)) という本も読んでおり、今回つくったサイトはPWAにも、なっている。

f:id:a-know:20200220093611p:plain:w480

Try PWA (技術の泉シリーズ(NextPublishing))

Try PWA (技術の泉シリーズ(NextPublishing))

  • 作者:渋田 達也
  • 発売日: 2019/11/08
  • メディア: オンデマンド (ペーパーバック)

PWAの魅力自体を気づかせてくれたのは Scrapbox なのだけど、実際に自分の持ち物をPWAに対応させてみて、「やはり、これはイイ......!」となった。今後もReact(Next.js)x PWA、やっていくぞ!

オマケのオマケ

今回つくったサイトはどこで動いているかというと、今流行りのアレやコレではなく、(僕にとって馴染みの深い)Google App Engine。

github.com

Java や Go のプロジェクトはいくつか作ってきたけど、node のプロジェクトは今回が初。でも、特にこれといって迷うことなくデプロイ&動作を確認することができた。やっぱりGAEは最高だな!!