20200911のReactに関する記事は11件です。

create-react-appを使用したReactの環境構築(TypeScriptも)

はじめに

久々、環境構築をしたのでまとめました。
今回はcreate-react-appを使用してreactの環境構築をしていきます
どなたかの参考になれば。

環境

まずは作業を始める段階でのバージョンです。
homebrewは入っている前提で作業を進めていきます。

名前 version 補足
MacOS 10.15 Catalina
homebrew 2.5
node.js 12.9
yarn 1.22 stable
create-react-app 3.4

以下、今回インストールする物のバージョンです。

名前 version 補足
nodebrew 1.0
node.js 14.10 stable 更新します
yarn 1.22 stable
create-react-app 3.4

nodebrewのインストール

まずhomebrewを使用して、nodebrewをインストールしていきます。
既にnode.jsが入っているので必要ないといえばないのですが、後々のことを考えてnodebrewを使用することにしました。
まずはインストール。

$ brew install nodebrew

私の場合、エラーが出ました。出なかった人はスルーしてください。
gccをインストールしないとビルド出来ないよとの事なのでインストールします。
終わったら再度nodebrewをインストールします。

Error: An exception occurred within a child process:
  CompilerSelectionError: nodebrew cannot be built with any available compilers.
Install GNU's GCC:
  brew install gcc

インストールが終了したら確認
バージョンが表示されたら成功です。

$ nodebrew --version

nodebrewがインストールされたらpathを通します。
私はCatalinaなのでzshですがbashの人は.bashrcで入力してください。
もちろんvimで直接入力しても問題ありません。

$ nodebrew setup

export...とパスが表示されるのでそれをコピーして↓のコマンドを入力
$ echo '{コピペしたやつ}' >> ~/.zshrc

次にnode.jsの安定版をインストールします。
バージョンを指定したい場合はstableの部分を指定のバージョンを書き入れましょう。
迷ったらとりあえず安定版。

$ nodebrew install-binary stable

インストールされていたら確認と指定をしていきます。

インストール出来ているか確認します
$ nodebrew list

今回はv14.10.1がインストールされていたのでこちらを使用します。
$ nodebrew use 14.10.1

nodeのバージョンを確認。14.10.1になっていればOKです
$ node -v

以上で、nodebrewとnode.jsのインストールは終了です。

react.jsの環境構築

yarnのインストール

node.jsのパッケージマネージャーであるyarnをインストールします。
こちらもhomebrewから。

$ brew install yarn

終わったら確認

$ yarn --version

react-create-app

reactはreact-create-appを使用するのが一番楽なのでyarnからこちらをインストールします。

$ yarn global add create-react-app

インストールされたら使用可能です!

$ create-react-app {名前}

まとめ

最近、自分のPCで開発をしていなかったので、なかなか長い道のりになりました。
作業を進めながら書いたので抜けはないかと思いますが、何かありましたらコメントお願いいたします!
近々react+typescriptの環境構築もするので、そちらもまとめますー!

追記

TypeScriptの設定を調べたのですが、どうやらcreate-react-appで簡単に設定出来るようです...!

$ create-react-app {アプリ名} --typescript

オプションを指定するだけで行けるらしいです...!簡単!!

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

create-react-appを使用したReactの環境構築

はじめに

久々、環境構築をしたのでまとめました。
今回はcreate-react-appを使用してreactの環境構築をしていきます
どなたかの参考になれば。

環境

まずは作業を始める段階でのバージョンです。
homebrewは入っている前提で作業を進めていきます。

名前 version 補足
MacOS 10.15 Catalina
homebrew 2.5
node.js 12.9
yarn 1.22 stable
create-react-app 3.4

以下、今回インストールする物のバージョンです。

名前 version 補足
nodebrew 1.0
node.js 14.10 stable 更新します
yarn 1.22 stable
create-react-app 3.4

nodebrewのインストール

まずhomebrewを使用して、nodebrewをインストールしていきます。
既にnode.jsが入っているので必要ないといえばないのですが、後々のことを考えてnodebrewを使用することにしました。
まずはインストール。

$ brew install nodebrew

私の場合、エラーが出ました。出なかった人はスルーしてください。
gccをインストールしないとビルド出来ないよとの事なのでインストールします。
終わったら再度nodebrewをインストールします。

Error: An exception occurred within a child process:
  CompilerSelectionError: nodebrew cannot be built with any available compilers.
Install GNU's GCC:
  brew install gcc

インストールが終了したら確認
バージョンが表示されたら成功です。

$ nodebrew --version

nodebrewがインストールされたらpathを通します。
私はCatalinaなのでzshですがbashの人は.bashrcで入力してください。
もちろんvimで直接入力しても問題ありません。

$ nodebrew setup

export...とパスが表示されるのでそれをコピーして↓のコマンドを入力
$ echo '{コピペしたやつ}' >> ~/.zshrc

次にnode.jsの安定版をインストールします。
バージョンを指定したい場合はstableの部分を指定のバージョンを書き入れましょう。
迷ったらとりあえず安定版。

$ nodebrew install-binary stable

インストールされていたら確認と指定をしていきます。

インストール出来ているか確認します
$ nodebrew list

今回はv14.10.1がインストールされていたのでこちらを使用します。
$ nodebrew use 14.10.1

nodeのバージョンを確認。14.10.1になっていればOKです
$ node -v

以上で、nodebrewとnode.jsのインストールは終了です。

react.jsの環境構築

yarnのインストール

node.jsのパッケージマネージャーであるyarnをインストールします。
こちらもhomebrewから。

$ brew install yarn

終わったら確認

$ yarn --version

react-create-app

reactはreact-create-appを使用するのが一番楽なのでyarnからこちらをインストールします。

$ yarn global add create-react-app

インストールされたら使用可能です!

$ create-react-app {名前}

まとめ

最近、自分のPCで開発をしていなかったので、なかなか長い道のりになりました。
作業を進めながら書いたので抜けはないかと思いますが、何かありましたらコメントお願いいたします!
近々react+typescriptの環境構築もするので、そちらもまとめますー!

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【TypeScript・Redux ToolKit】特定の型だけを受け入れるActionCreaterを作る

@reduxjs/toolkit-1.4.0

はじめに

Redux-ToolKitcreateAction()で定義するActionCreaterは、基本的にどんな引数も受け入れてしまいます。

受け付ける型を制限し、コントロールされたpayloadのみを受け入れるようにカスタムする方法を紹介します。

通常のActionCreater

createAction()の引数に与えたtypeを持つアクションオブジェクトを返すActionCreaterを定義できます。

import { createAction } from '@reduxjs/toolkit';

const addTodo = createAction('ADD_TODO');
addTodo('Study Redux with TypeScript');

// { type: "ADD_TODO", payload: "Study Redux with TypeScript" }

問題は、得られたActionCreaterであるaddTodo()という関数がどんな引数も受け入れてしまうことです。

ここでは、payloadとして文字列のみ受け付けたいとします。

特定の型だけを受け入れるActionCreater

ジェネリクスを与えます。これだけ。

const addTodo = createAction<string>('ADD_TODO');

まとめ

createAction<T>(arg)とすることで、特定の型だけを受け入れるActionCreaterを定義できました。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【技術選定】React.js vs Vue.jsを真剣に評価してみた

目次

1. 対象読者
2. 目的
3. 技術選定の考え方
4. 評価基準
5. 結論
6. 比較評価
7. テックリード/エンジニア募集中!

1. 対象読者

React.jsとVue.jsどちらを採用するか?
を悩んでいるフロントエンドのアーキテクトや開発者向けです。

2. 目的

適切な技術選定の手助けとなれればと思います。

3. 技術選定の考え方

技術は要件を満たすための手段です。
そのため、技術選定では、求められる要件をまず明確にするべきです。
そして、要件を最も満たす技術を採用するべきです。

4. 評価基準

上記の考え方に基づき、よくある要件ごとにReact.js vs Vue.jsを比較評価しました。

  • 多角的&客観的に評価するよう心掛けました。
  • 主観的な評価の場合、個人見解である旨を明記しました。

【よくある要件をどう網羅したか】

要件は、機能要件/非機能要件に分けられます。

  • 機能要件は、多種多様なので網羅困難です。よくありそうな要件(個人見解)のみにしました。
  • 非機能要件はIPAの非機能要求グレードを参考に網羅しました。

5. 結論

  • 可用性を細かく気にする場合、Vue.jsの方が未解決バグ数は少ないです。(可用性の詳細)
  • テーブルの行入れ替えが多いシステムの場合、Vue.jsを選択した方が良いです。(性能の詳細)
  • 海外の開発者が必要な場合、React.jsを選択した方が「やや良い」です。(開発者確保の詳細)
  • 学習コストを重視する場合、React.jsを選択した方が良いです。(学習コストの詳細)
  • それ以外の場合、どちらを選択しても良いです。

【比較表】

評価項目 React Vue
可用性 ○※1
保守性
セキュリティ
性能 ○※2 ○※2
開発者の確保しやすさ
学習コスト
優れたUIの提供しやすさ
開発者が楽しい ○※3 ○※3

※1 ただし、未解決バグ数がReact.jsの方が多いです。(可用性の詳細)
※2 大きな問題はありませんが、それぞれに得意/不得意があります。(性能の詳細)
※3 個人見解です。

上記結論に至った詳細は、以下の通りです。

6. 比較評価

6.1 可用性

安定して継続的に本番稼動できる品質か?という観点で評価しました。

【結論】

引き分けです。未解決バグ数を気にされる場合は、Vue.jsの勝利です。

【理由】

どちらも本番運用実績が十分にある&十分な頻度で改修されているからです。
未解決バグ数はReact.jsの方が数字的には多いです。
個人見解としては気にするほどの差異ではありませんが、気にされる場合はVue.jsの勝利です。
詳細は以下の通りです。

【本番運用実績】

どちらも十分な実績があります。

  • React.js:Facebook,Uber,Tesla等
  • Vue.js:Google, Apple, Nintendo, Gitlab等

【未解決バグ数】

React.jsの方がやや多いです。
GitのIssuesの「bug」タグの数を見ると以下です。(2020/09時点)

※本来ならバグ率で比較したかったですが、規模が分からないので断念しました。
※バグ毎の重要度も異なりますので、バグ数はあくまでも参考値という扱いですね。

【改修頻度】

どちらもすごい頻度で改修されています。
GitのReleasesから2019年のリリース回数を数えると以下です。

6.2 保守性

【結論】

引き分けです。

【理由】

どちらもコンポーネント単位で開発できるため、保守性を確保しやすいからです。
もちろん技術選定以前に、保守性を確保した設計ができていることが大事です。

6.3 セキュリティ

【結論】

引き分けです。

【理由】

以下の通り、セキュリティ対策内容に差異が無いためです。

主にフロントエンド側のセキュリティ対策を対象に調査しました。
どちらもXSS対策が組み込まれています。
具体的には以下の通りです。

6.3.1 XSS(クロスサイトスクリプティング)

【XSSとは】

Webアプリに罠リンク等を表示できてしまう脆弱性のことです。

悪意のあるユーザが悪意のあるスクリプトやHTMLを入力したとき、
対策されていないWebアプリだと、罠リンク等が表示されてしまいます。

罠リンクをクリックしたユーザは、例えばログインセッション情報を盗まれ、不正ログイン(なりすまし)されてしまったり、様々な被害を受けます。

詳細は、「3分でわかるXSSとCSRFの違い」が分かりやすいと思います。

【React.jsのXSS対策】

対策されています。自動でサニタイズ(エスケープ)してくれます。

公式 | JSX はインジェクション攻撃を防ぐ
デフォルトでは、React DOM は JSX に埋め込まれた値をレンダリングされる前にエスケープします。このため、自分のアプリケーションで明示的に書かれたものではないあらゆるコードは、注入できないことが保証されます。レンダーの前に全てが文字列に変換されます。これは XSS (cross-site-scripting) 攻撃の防止に役立ちます。

:warning: dangerouslySetInnerHTMLを使用する場合はサニタイズされませんので、脆弱性につながるリスクがあります。スクリプトに該当する文字列をサニタイズする等の対策が必要です。

公式 | dangerouslySetInnerHTML
dangerouslySetInnerHTML は、ブラウザ DOM における innerHTML の React での代替です。一般に、コードから HTML を設定することは、誤ってあなたのユーザをクロスサイトスクリプティング (XSS) 攻撃に晒してしまいやすいため、危険です。

※GoogleデベロッパーエキスパートでAuth0アンバサダー/エキスパートであるPhilippe De Ryck氏がReact.jsのXSS対策の記事を書いており、参考になります。
Preventing XSS in React

※サニタイズとは、ユーザ入力値に含まれるHTML/JavaScript特殊文字をエスケープすることで、HTML/JavaScriptとして解釈されないようにすることです。

【Vue.jsのXSS対策】

対策されています。自動でサニタイズ(エスケープ)してくれます。

公式 | セキュリティ
テンプレートを使用する場合も、描画関数を使用する場合も、コンテンツは自動的にエスケープ処理されます。

:warning: ただし、v-htmldomPropsInnerHTMLを使用する場合はサニタイズされませんので、脆弱性につながるリスクがあります。スクリプトに該当する文字列をサニタイズする等の対策が必要です。

:warning: SSR(サーバサイドレンダリング)に乗せると、脆弱性につながる場合があります。こちらのサイトが参考になります。

6.3.2 XSS以外

【評価】

React.jsとVue.jsどちらも対策の仕組みはありません。
基本的にフロントエンドではなくバックエンドやミドルウェアで対策するものだからでしょう。

【補足】

:warning: とはいえ例えば、CSRF対策のトークンをリクエストヘッダに埋め込む等の実装は必要ですね。
サーバで発行したCSRFトークンを、リクエスト毎にヘッダに設定するイメージです。
React.js or Vue.js問わず、Axios等で実装すると思いますが、
Vue.jsならこの記事、React.jsならこの記事が、参考になるかもしれません。

6.4 性能

【結論】

引き分けです。

【理由】

一部で得意/不得意の差があるものの、処理時間/メモリ使用量ともに互角です。
詳細は以下の通りです。

【処理時間】

ベンチマークサイトによると、それぞれに得意/不得意があります。
※react-v16.4.1、vue-v2.5.16の「keyed」を比較しました。

  • React.jsは、テーブルの行入れ替えがVue.jsよりも遅いです。
  • Vue.jsは、テーブル行の部分更新がReact.jsよりも遅いです。
  • それ以外の処理時間は、どちらも互角です。

以下は、ベンチマークサイトの結果から作成した表です。
paformance.png

【メモリ使用量】

ベンチマークサイトによると、どちらも互角です。
※react-v16.4.1、vue-v2.5.16の「keyed」を比較しました。

6.5 開発者の確保しやすさ

【結論】

国内は引き分け、海外は僅差でReact.jsの勝利です。

【理由】

どちらも人気(≒開発者が多い)だからです。
Googleトレンドでは海外だとReact.jsの方が多いです。
具体的には、以下の通りです。

【人気度】

React.jsとVue.jsともに、人気度/要望度がトップです。

StackOverflow_React_Vue.PNG
https://insights.stackoverflow.com/survey/2019#technology

【GitのStar数】

どちらも同等の人気があります。

【Googleトレンド】

React.jsとVue.jsのGoogleトレンドは、国内は引き分け、海外はReact.jsの勝利です。

※国内はこちら↓

GoogleTrend_React_Vue_JP.PNG

※海外はこちら↓

GoogleTrend_React_Vue.PNG

6.6 学習コスト

【結論】

定量評価だとReact.jsの勝利、定性評価だとVue.jsの勝利(個人見解)です。
客観的に見れば、定量評価を優先してReact.jsの勝利です。

【理由】

定量評価だと、Vue.jsの方が覚える量が物理的に多いからです。
具体的には以下の通りです。

6.6.1 定量評価:React.jsの勝利

【評価】

JSX記法より、Vue.js構文の方が覚える量が物理的に多いです。
それ以外のstateやRouter等の学習量は、React.jsとVue.jsでほぼ差異はありません。
詳細は以下の通りです。

【React.jsで学習が必要なこと】

主に以下の学習が必要です。

  • JSX記法
  • state/Redux
  • Router/hook等

【Vue.jsで学習が必要なこと】

主に以下の学習が必要です。

  • Vue.js構文(各種ディレクティブ/computed/watch/method等)
  • state/Vuex
  • Router等

6.6.2 定性評価:Vue.jsの勝利(個人見解)

【評価】

Vue.jsの方が学習しやすいです。個人見解です。

【理由】

個人見解ですが、見慣れないJSX記法より、HTMLっぽく読めるVue.jsの方が、抵抗感無く学習できたからです。
※慣れてしまった今はJSX記法への抵抗感は無いですが、当初は抵抗感があったという意味です。

6.7 優れたUIの提供しやすさ

【結論】

引き分けです。

【理由】

以下の通り、「優れたUI」を実装するコストに差異が無いためです。

【優れたUIの定義】

この記事では、ユーザーが考えずに操作できるUIを「優れたUI」と定義します。
※参考:Steve Krug著「Don't Make Me Think」

優れたUIの具体例は以下です。
・どれがクリックできる要素か?が明確であること。
・説明がシンプル&明確であること。(自己満足な宣伝文句が無い)

【評価観点】

まず、設計工程で「優れたUI」が設計されている必要があります。
その前提で、React.jsとVue.jsのどちらが実装コストが少ないか?で評価します。

【評価】

実装コストに差異は無いでしょう。

  • UIフレームワークで実現できるUIデザインの場合
    • React.jsなら「Material-UI」等、Vue.jsなら「Vuetify」等で実装できます。
  • 上記で実現できない凝ったUIデザインの場合
    • React.js or Vue.jsに関わらず、UIフレームワークのカスタマイズや独自CSSの実装が必要です。

6.8 開発者が楽しい

開発者のモチベーションは大事ですね。

【結論】

引き分けです。

【理由】

開発者の主観で決まりますので引き分けです。
個人見解としては、どちらも楽しいです。

7. テックリード/エンジニア募集中!

株式会社ビジョン・コンサルティングでは、アーキテクトや開発者を募集しています!
世界をより便利にすることに情熱を燃やし、新規事業部で新サービスを一緒に開発しませんか?
詳細はこちら

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

React.js vs Vue.jsを真剣に評価してみたら、巷の評価とは違う結果になった

目次

1. 対象読者
2. 目的
3. 技術選定の考え方
4. 評価基準
5. 結論 | 比較表
6. 比較評価
7. テックリード/エンジニア募集中!

1. 対象読者

React.jsとVue.jsどちらを採用するか?
を悩んでいるフロントエンドのアーキテクトや開発者向けです。

2. 目的

適切な技術選定の手助けとなれればと思います。

3. 技術選定の考え方

技術は要件を満たすための手段です。
そのため、技術選定では、求められる要件をまず明確にするべきです。
そして、要件を最も満たす技術を採用するべきです。

4. 評価基準

上記の考え方に基づき、よくある要件ごとにReact.js vs Vue.jsを比較評価しました。

  • 多角的&客観的に評価するよう心掛けました。
  • 主観的な評価の場合、個人見解である旨を明記しました。

【よくある要件をどう網羅したか】

要件は、機能要件/非機能要件に分けられます。

  • 機能要件は、多種多様なので網羅困難です。よくありそうな要件(個人見解)のみにしました。
  • 非機能要件はIPAの非機能要求グレードを参考に網羅しました。

5. 結論 | 比較表

  • 可用性を細かく気にする場合、Vue.jsの方が未解決バグ数は少ないです。(可用性の詳細)
  • テーブルの行入れ替えが多いシステムの場合、Vue.jsを選択した方が良いです。(性能の詳細)
  • 海外の開発者が必要な場合、React.jsを選択した方が「やや良い」です。(開発者確保の詳細)
  • 学習コストを重視する場合、React.jsを選択した方が良いです。(学習コストの詳細)
  • それ以外の場合、どちらを選択しても良いです。

【比較表】

評価項目 React Vue
可用性 ○※1
保守性
セキュリティ
性能 ○※2 ○※2
開発者の確保しやすさ
学習コスト
優れたUIの提供しやすさ
開発者が楽しい ○※3 ○※3

※1 ただし、未解決バグ数がReact.jsの方が多いです。(可用性の詳細)
※2 大きな問題はありませんが、それぞれに得意/不得意があります。(性能の詳細)
※3 個人見解です。

上記結論に至った詳細は、以下の通りです。

6. 比較評価

6.1 可用性

安定して継続的に本番稼動できる品質か?という観点で評価しました。

【結論】

引き分けです。未解決バグ数を気にされる場合は、Vue.jsの勝利です。

【理由】

どちらも本番運用実績が十分にある&十分な頻度で改修されているからです。
未解決バグ数はReact.jsの方が数字的には多いです。
個人見解としては気にするほどの差異ではありませんが、気にされる場合はVue.jsの勝利です。
詳細は以下の通りです。

【本番運用実績】

どちらも十分な実績があります。

  • React.js:Facebook,Uber,Tesla等
  • Vue.js:Google, Apple, Nintendo, Gitlab等

【未解決バグ数】

React.jsの方がやや多いです。
GitのIssuesの「bug」タグの数を見ると以下です。(2020/09時点)

※本来ならバグ率で比較したかったですが、規模が分からないので断念しました。
※バグ毎の重要度も異なりますので、バグ数はあくまでも参考値という扱いですね。

【改修頻度】

どちらもすごい頻度で改修されています。
GitのReleasesから2019年のリリース回数を数えると以下です。

6.2 保守性

【結論】

引き分けです。

【理由】

どちらもコンポーネント単位で開発できるため、保守性を確保しやすいからです。
もちろん技術選定以前に、保守性を確保した設計ができていることが大事です。

6.3 セキュリティ

【結論】

引き分けです。

【理由】

以下の通り、セキュリティ対策内容に差異が無いためです。

主にフロントエンド側のセキュリティ対策を対象に調査しました。
どちらもXSS対策が組み込まれています。
具体的には以下の通りです。

6.3.1 XSS(クロスサイトスクリプティング)

【XSSとは】

Webアプリに罠リンク等を表示できてしまう脆弱性のことです。

悪意のあるユーザが悪意のあるスクリプトやHTMLを入力したとき、
対策されていないWebアプリだと、罠リンク等が表示されてしまいます。

罠リンクをクリックしたユーザは、例えばログインセッション情報を盗まれ、不正ログイン(なりすまし)されてしまったり、様々な被害を受けます。

詳細は、「3分でわかるXSSとCSRFの違い」が分かりやすいと思います。

【React.jsのXSS対策】

対策されています。自動でサニタイズ(エスケープ)してくれます。

公式 | JSX はインジェクション攻撃を防ぐ
デフォルトでは、React DOM は JSX に埋め込まれた値をレンダリングされる前にエスケープします。このため、自分のアプリケーションで明示的に書かれたものではないあらゆるコードは、注入できないことが保証されます。レンダーの前に全てが文字列に変換されます。これは XSS (cross-site-scripting) 攻撃の防止に役立ちます。

:warning: dangerouslySetInnerHTMLを使用する場合はサニタイズされませんので、脆弱性につながるリスクがあります。スクリプトに該当する文字列をサニタイズする等の対策が必要です。

公式 | dangerouslySetInnerHTML
dangerouslySetInnerHTML は、ブラウザ DOM における innerHTML の React での代替です。一般に、コードから HTML を設定することは、誤ってあなたのユーザをクロスサイトスクリプティング (XSS) 攻撃に晒してしまいやすいため、危険です。

※GoogleデベロッパーエキスパートでAuth0アンバサダー/エキスパートであるPhilippe De Ryck氏がReact.jsのXSS対策の記事を書いており、参考になります。
Preventing XSS in React

※サニタイズとは、ユーザ入力値に含まれるHTML/JavaScript特殊文字をエスケープすることで、HTML/JavaScriptとして解釈されないようにすることです。

【Vue.jsのXSS対策】

対策されています。自動でサニタイズ(エスケープ)してくれます。

公式 | セキュリティ
テンプレートを使用する場合も、描画関数を使用する場合も、コンテンツは自動的にエスケープ処理されます。

:warning: ただし、v-htmldomPropsInnerHTMLを使用する場合はサニタイズされませんので、脆弱性につながるリスクがあります。スクリプトに該当する文字列をサニタイズする等の対策が必要です。

:warning: SSR(サーバサイドレンダリング)に乗せると、脆弱性につながる場合があります。こちらのサイトが参考になります。

6.3.2 XSS以外

【評価】

React.jsとVue.jsどちらも対策の仕組みはありません。
基本的にフロントエンドではなくバックエンドやミドルウェアで対策するものだからでしょう。

【補足】

:warning: とはいえ例えば、CSRF対策のトークンをリクエストヘッダに埋め込む等の実装は必要ですね。
サーバで発行したCSRFトークンを、リクエスト毎にヘッダに設定するイメージです。
React.js or Vue.js問わず、Axios等で実装すると思いますが、
Vue.jsならこの記事、React.jsならこの記事が、参考になるかもしれません。

6.4 性能

【結論】

引き分けです。

【理由】

一部で得意/不得意の差があるものの、処理時間/メモリ使用量ともに互角です。
詳細は以下の通りです。

【処理時間】

ベンチマークサイトによると、それぞれに得意/不得意があります。
※react-v16.4.1、vue-v2.5.16の「keyed」を比較しました。

  • React.jsは、テーブルの行入れ替えがVue.jsよりも遅いです。
  • Vue.jsは、テーブル行の部分更新がReact.jsよりも遅いです。
  • それ以外の処理時間は、どちらも互角です。

以下は、ベンチマークサイトの結果から作成した表です。
paformance.png

【メモリ使用量】

ベンチマークサイトによると、どちらも互角です。
※react-v16.4.1、vue-v2.5.16の「keyed」を比較しました。

6.5 開発者の確保しやすさ

【結論】

国内は引き分け、海外は僅差でReact.jsの勝利です。

【理由】

どちらも人気(≒開発者が多い)だからです。
Googleトレンドでは海外だとReact.jsの方が多いです。
具体的には、以下の通りです。

【人気度】

React.jsとVue.jsともに、人気度/要望度がトップです。

StackOverflow_React_Vue.PNG
https://insights.stackoverflow.com/survey/2019#technology

【GitのStar数】

どちらも同等の人気があります。

【Googleトレンド】

React.jsとVue.jsのGoogleトレンドは、国内は引き分け、海外はReact.jsの勝利です。

※国内はこちら↓

GoogleTrend_React_Vue_JP.PNG

※海外はこちら↓

GoogleTrend_React_Vue.PNG

6.6 学習コスト

【結論】

定量評価だとReact.jsの勝利、定性評価だとVue.jsの勝利(個人見解)です。
客観的に見れば、定量評価を優先してReact.jsの勝利です。

【理由】

定量評価だと、Vue.jsの方が覚える量が物理的に多いからです。
具体的には以下の通りです。

6.6.1 定量評価:React.jsの勝利

【評価】

JSX記法より、Vue.js構文の方が覚える量が物理的に多いです。
それ以外のstateやRouter等の学習量は、React.jsとVue.jsでほぼ差異はありません。
詳細は以下の通りです。

【React.jsで学習が必要なこと】

主に以下の学習が必要です。

  • JSX記法
  • state/Redux
  • Router/hook等

【Vue.jsで学習が必要なこと】

主に以下の学習が必要です。

  • Vue.js構文(各種ディレクティブ/computed/watch/method等)
  • state/Vuex
  • Router等

6.6.2 定性評価:Vue.jsの勝利(個人見解)

【評価】

Vue.jsの方が学習しやすいです。個人見解です。

【理由】

個人見解ですが、見慣れないJSX記法より、HTMLっぽく読めるVue.jsの方が、抵抗感無く学習できたからです。
※慣れてしまった今はJSX記法への抵抗感は無いですが、当初は抵抗感があったという意味です。

6.7 優れたUIの提供しやすさ

【結論】

引き分けです。

【理由】

以下の通り、「優れたUI」を実装するコストに差異が無いためです。

【優れたUIの定義】

この記事では、ユーザーが考えずに操作できるUIを「優れたUI」と定義します。
※参考:Steve Krug著「Don't Make Me Think」

優れたUIの具体例は以下です。
・どれがクリックできる要素か?が明確であること。
・説明がシンプル&明確であること。(自己満足な宣伝文句が無い)

【評価観点】

まず、設計工程で「優れたUI」が設計されている必要があります。
その前提で、React.jsとVue.jsのどちらが実装コストが少ないか?で評価します。

【評価】

実装コストに差異は無いでしょう。

  • UIフレームワークで実現できるUIデザインの場合
    • React.jsなら「Material-UI」等、Vue.jsなら「Vuetify」等で実装できます。
  • 上記で実現できない凝ったUIデザインの場合
    • React.js or Vue.jsに関わらず、UIフレームワークのカスタマイズや独自CSSの実装が必要です。

6.8 開発者が楽しい

開発者のモチベーションは大事ですね。

【結論】

引き分けです。

【理由】

開発者の主観で決まりますので引き分けです。
個人見解としては、どちらも楽しいです。

7. テックリード/エンジニア募集中!

株式会社ビジョン・コンサルティングでは、アーキテクトや開発者を募集しています!
世界をより便利にすることに情熱を燃やし、新規事業部で新サービスを一緒に開発しませんか?
詳細はこちら

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【React】クラスコンポーネント /関数コンポーネントの違いと使い分け。なぜ 関数コンポーネントが好まれるのか。

はじめに

どうもシュータといいます!
2019年、 React 16.8のリリースに伴いHooksが導入され、
stateやlife cycle methodを使用する際はClass Componentを使用した方が良いという判断が実情に合わなくなってしまったように思います。
この記事では今一度、クラスコンポーネントと関数コンポーネントの違いを明らかにしつつ、Hooksの導入に伴いどう変化したか、
そして関数コンポーネントが好まれやすいのは何故かという理由を記載します。

関数コンポーネントとクラスコンポーネント

まず関数コンポーネントとクラスコンポーネントで
シンプルなコンポーネントを作成した例を示します。

関数コンポーネント
function Welcome(props) {
  return <h1>Hello, {props.name} </h1>;
}

こちらは基本的なjavascriptの関数と同様です。
propsを受け取り、使用することが可能です。

クラスコンポーネント
class Welcome extends React.Component {
  render() {
    return <h1>Hello, {this.props.name}</h1>;
  }
}

こちらはReactのCompoentクラスを継承しています。
クラスコンポーネントでもpropsを受け取り
使用することは可能です。

Hooks導入以前の関数コンポーネントとクラスコンポーネントの主な違い

クラスコンポーネントでは関数コンポーネントと異なり、コンポーネント内で下記の二つを使用することができます。

  • state(状態管理)
  • Lifecycle method

stateの例

class Welcome extends React.Component {
  constructor(props){
    super(props)
    this.state = {
    name: "hoge"
    }
  }
  render() {
    return <h1>Hello, {this.state.name}</h1>;
  }
}

Lifecycle methodの例

詳しくはこちらをご覧ください。

class Welcome extends React.Component {
  constructor(props){
    super(props)
    this.state = {
    name: "hoge"
    }
  }

 componentDidMount() {
   this.setState({name:"fuga"})
  }
 
  render() {
    return <h1>Hello, {this.state.name}</h1>;
  }
}

Hooks導入後

HooKs導入前は関数コンポーネントとクラスコンポーネントは
前述のような違いがありましたが
Hooksの登場により、関数コンポーネントでも
状態管理やライフサイクルの機能を使用できるようになりました。
そしてそれらはクラスコンポーネントで記述するよりも
簡潔に書くことが可能です。

状態管理

Hooksを利用した関数コンポーネントで状態管理する例

import React, { useState } from 'react';

function Example() {
  // Declare a new state variable, which we'll call "count"
  const [count, setCount] = useState(0);

  return (
    <div>
      <p>You clicked {count} times</p>
      <button onClick={() => setCount(count + 1)}>
        Click me
      </button>
    </div>
  );
}

同様のコンポーネントをクラスコンポーネントで書いた場合
class Example extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      count: 0
    };
  }

  render() {
    return (
      <div>
        <p>You clicked {this.state.count} times</p>
        <button onClick={() => this.setState({ count: this.state.count + 1 })}>
          Click me
        </button>
      </div>
    );
  }
}

ライフサイクル

Hooksを利用した関数コンポーネントでライフサイクルメソッドを使う例
import React, { useState, useEffect } from 'react';

function Example() {
  const [count, setCount] = useState(0);

  // Similar to componentDidMount and componentDidUpdate:
  useEffect(() => {
    // Update the document title using the browser API
    document.title = `You clicked ${count} times`;
  });

  return (
    <div>
      <p>You clicked {count} times</p>
      <button onClick={() => setCount(count + 1)}>
        Click me
      </button>
    </div>
  );

同様のコンポーネントをクラスコンポーネントで書いた場合
class Example extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      count: 0
    };
  }

  componentDidMount() {
    document.title = `You clicked ${this.state.count} times`;
  }
  componentDidUpdate() {
    document.title = `You clicked ${this.state.count} times`;
  }

  render() {
    return (
      <div>
        <p>You clicked {this.state.count} times</p>
        <button onClick={() => this.setState({ count: this.state.count + 1 })}>
          Click me
        </button>
      </div>
    );
  }
}

なぜ関数コンポーネントが好まれるか

  • コードが簡潔にかける

これまでみてきたように
関数コンポーネントで記述することによってより見通しの良いコードがかけることに気付いていただけたと思います。

  • Viewからの複雑さを排除することも可能となる

これまで示した例だけでなく、データフロー全体の設計からの観点となりますがコンポーネントになるべく状態を持たせない設計や、view以外ファイルにAPI通信などの副作用を局所化させる設計を行うことより
viewの責務を軽くすることも可能です。
将来的にReact以外のライブラリ、フレームワークを使用することになった際も乗り換えやすくなることが期待できます。

 最後に

読んでくださった方ありがとうございました!

誤字脱字・間違い等ございましたら、指摘して頂けますと幸いです!
また、説明にわかりづらい点がございましたら、改善致しますのでぜひコメントください。

reference

https://reactjs.org/

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

5分でわかる useContext の使い方【TypeScriptまで】

できるだけシンプルに useContext の使い方を解説。

useContextとはそもそも何

useContext とは親より全ての子(孫)がプロパティや値をグローバルに扱えるようにする Hook(または親以下をスコープにするHookとも言える)。
したがって、親に埋め込まれていないコンポーネントへは値を渡すことはできない。

useState と合わせて使うことで props のバケツリレーをせずに状態を更新できるようになるのがメリット。
バケツリレーの複雑さを避けるために使えるかと。

使い方

  1. createContext() で親に初期値を渡す(createContextをimport)
  2. useContext() で子や孫で受け取る(useContextをimport)

単純なサンプル

Parent.js
Child.js
ChildChild.js
ChildChildChild.js
で親から孫のファイルを作った。ネストさせてコンポートネントを埋め込んでいる。
まずは useState などは使わずに使ってみることに。

Parent.js では createContext で初期値を設定している。宣言した 変数Context がグローバルで扱える変数となる。

Parent.js
import React, { createContext } from "react";
import Child from "./Child";

export const Context = createContext("私はContextです。propsで渡してもらっていません。");

const Parent = () => (
    <>
      <h1>親です</h1>
      <Child />
    </>
 );

export default Parent;

Child.js以降では useContext(Context) で 親の createContext を使って宣言した 変数Context を呼び出すことができる。

Child.js
import React, { useContext } from "react";
import ChildChild from "./ChildChild";
import { Context } from "./Parent";

const Child = () => {
  const ChildContext = useContext(Context);
  return (
    <>
      <h2>Childです</h2>
      <p>{ChildContext}</p>
      <ChildChild />
    </>
  );
};
export default Child;

ChildChild.js
import React, { useContext } from "react";
import ChildChildChild from "./ChildChildChild";
import { Context } from "./Parent";

const ChildChild = () => {
  const ChildChildContext = useContext(Context);

  return (
    <>
      <h2>ChildChildです</h2>
      <p>{ChildChildContext}</p>
      <ChildChildChild />
    </>
  );
};

export default ChildChild;

ChildChildChild.js
import React, { useContext } from "react";
import { Context } from "./Parent";

const ChildChildChild = () => {
  const ChildChildChildContext = useContext(Context);

  return (
    <>
      <h2>ChildChildChildです</h2>
      <p>{ChildChildChildContext}</p>
    </>
  );
};

export default ChildChildChild;

このようにpropsを使わずに値を呼び出すことができた。

useContextの値の更新

今度は先ほどのサンプルを元に useState と合わせて使う。
といっても useState で状態を設定したら親側に Context.Provider というタグを埋め込みそこに state を設定するだけ。

codesandbox: https://codesandbox.io/s/weathered-dawn-buyky?fontsize=14&hidenavigation=1&theme=dark

Parent.js
import React, { useState, createContext } from "react";
import Child from "./Child";

export const Context = createContext();

const Parent = () => {
  const [state, setState] = useState(
    "私はContextです。propsで渡してもらっていません。"
  );
  const updateContext = () => setState("Contextを更新したよ。");

  return (
    <>
      <h1>親です</h1>
      <button onClick={updateContext}>contextを更新するボタン</button>
      <Context.Provider value={state}>
        <Child />
      </Context.Provider>
    </>
  );
};

export default Parent;

Parent.js
      <button onClick={updateContext}>contextを更新するボタン</button>
      <Context.Provider value={state}>
        <Child />
      </Context.Provider>

更新ボタンで state を更新させる。
Context.Provider のタグは子コンポーネントを囲ってあげる。

Provider で設定された value が親より以下コンポーネントが参照する useContext の値となるのでそこにstateを設定すれば当然、状態を親以下のスコープで更新することができるようになる。

TypeScriptでuseContextを使う

こちらもcodesandboxでサンプルを用意した
https://codesandbox.io/s/optimistic-sea-x9c95?fontsize=14&hidenavigation=1&theme=dark)

Parent.tsx
import React, { FC, createContext, useState } from "react";
import Child from "./Child";

export type ContextType = string;
export const Context = createContext<ContextType>("");

const Parent: FC = () => {
  const [state, setState] = useState(
    "私はContextです。propsで渡してもらっていません。"
  );
  const updateContext = () => setState("Contextを更新したよ。");

  return (
    <>
      <h1>親です</h1>
      <button onClick={updateContext}>contextを更新するボタン</button>
      <Context.Provider value={state}>
        <Child />
      </Context.Provider>
    </>
  );
};

export default Parent;

Context を宣言するタイミングで型を付けてあげる

Parent.tsx
export type ContextType = string;
export const Context = createContext<ContextType>("");

type ContextType = string; と解説用に用意しているがオブジェクトなどの型を用意しておき、createContext と共に型を当てはめておきたい。

TypeScriptのuseContextの蛇足

export const Context = createContext<Partial<ContextType>>({});

蛇足として使ったことはないものの、オブジェクトを初期化する場合は Partial を使うことで初期化できるとのこと。
参考:Make useContext Data More Discoverable with Typescript

まとめてみた所感

useState との兼ね合いがわかりにくかったが記事において useContext 単体での動きと切り分けてまとめてみる比較的にシンプルな Hook だと思った。
あくまで useContext(createContex) はプロパティや値のスコープ拡張をするもの。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Next.jsのDynamic RoutesでSPA遷移

Issue

Next.jsのDynamic Routesを使っているページに対して普通にnext/link<Link>を使ってリンクを貼ると、遷移時にブラウザのロードが発生してしまってSPA遷移にならない。
最初、Next.jsじゃなくてReactの何かがおかしい?と思って軽くハマった。

import Link from 'next/link'

// これだとブラウザロードが発生してしまう
<Link href={`/posts/${post.id}`}>リンク</Link>

Solution

ドキュメントを見ると、next/link<Link>にはas属性というのが用意されており、「ブラウザのURLバーでレンダリングされるパスを示すもので、Dynamic Routesで使ってください」と書いてある。
じゃあhrefは何なのかと言うと、「pagesディレクトリの内部のパスです」とのこと。

要するに、例えばDynamic Routesでpages/posts/[post-id].jsxとしている場合は下記のように書けば良いらしいです。

import Link from 'next/link'

<Link href="/posts/[post-id]" as={`/posts/${post.id}`}>リンク</Link>

asの方に普段hrefに書いているような具体的なパスを書くんですね。何か違和感。。。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

[Emacs] Typescript+JSXをなるべくweb-modeで編集するための設定

はじめに

ReactやTypescriptなどについて調べていると,この界隈にはVSCodeユーザが多いように感じられます.Emacsユーザにとっては少し肩身が狭いです.

Emacsを使った React + JSX の開発において,Javascriptを使う場合はrjsx-modejs-modeでおおむね事足ります.しかし,Typescriptを使う場合は,このような既存のモードでは少し不十分です.

私はこれまでrjsx-modeweb-modetypescript-modeなどを切り替えてやりくりしていましたが,これは一筋縄では行きません.例えば,rjsx-modeで引数の型指定をした部分から先がすべてエラーになったり,web-modeに切り替えた途端にカラーテーマが適用されなくなるようなことが起きてしまいます.

そこで,Typescript + JSXの編集をなるべくweb-modeで行うことができるようにするべく,その設定を行いました.

なお,私の環境ではカラーテーマをtango-darkとしています.その他のテーマでは,もしかすると必要に応じて最後の設定を直す必要があるかもしれません.

設定内容

~/.emacs.d/init.elに以下の設定を追記しました.

~/.emacs.d/init.el
;; web-mode settings for TSX
(add-to-list 'auto-mode-alist '("\\.[jt]sx\\'" . web-mode))
(defun custom-web-mode-hook ()
  (setq web-mode-attr-indent-offset nil)
  (setq web-mode-markup-indent-offset 2)
  (setq web-mode-css-indent-offset 4)
  (setq web-mode-code-indent-offset 4)
  (setq indent-tabs-mode nil)
  (setq tab-width 2)
  (setq web-mode-enable-current-element-highlight t)
  (let ((case-fold-search nil))
    (highlight-regexp "\\_<number\\|string\\|boolean\\|enum\\|unknown\\|any\\|void\\|null\\|undefined\\|never\\|object\\|symbol\\_>" 'font-lock-type-face)))
(add-hook 'web-mode-hook 'custom-web-mode-hook)
;; Inherit colors from font-lock
(custom-set-faces
 '(web-mode-doctype-face
   ((t :inherit font-lock-doc-face)))
 '(web-mode-html-tag-face
   ((t :inherit font-lock-function-name-face)))
 '(web-mode-html-attr-name-face
   ((t :inherit font-lock-variable-name-face)))
 '(web-mode-html-attr-value-face
   ((t :inherit font-lock-string-face)))
 '(web-mode-comment-face
   ((t :inherit font-lock-comment-face)))
 '(web-mode-server-comment-face
   ((t :inherit font-lock-comment-face)))
 '(web-mode-javascript-comment-face
   ((t :inherit font-lock-comment-face)))
 '(web-mode-json-comment-face
   ((t :inherit font-lock-comment-face)))
 '(web-mode-error-face
   ((t :inherit font-lock-warning-face)))
 '(web-mode-current-element-highlight-face
   ((t :inherit font-lock-builtin-face)))
 '(web-mode-html-tag-bracket-face
   ((t :inherit font-lock-negation-char-face)))
 '(web-mode-block-delimiter-face
   ((t :inherit font-lock-negation-char-face)))
 '(web-mode-javascript-string-face
   ((t :inherit font-lock-string-face)))
 '(web-mode-json-key-face
   ((t :inherit font-lock-keyword-face)))
 '(web-mode-json-string-face
   ((t :inherit font-lock-string-face)))
 '(web-mode-keyword-face
   ((t :inherit font-lock-keyword-face)))
 '(web-mode-param-name-face
   ((t :inherit font-lock-variable-name-face)))
 '(web-mode-preprocessor-face
   ((t :inherit font-lock-preprocessor-face)))
 '(web-mode-string-face
   ((t :inherit font-lock-string-face)))
 '(web-mode-type-face
   ((t :inherit font-lock-type-face)))
 '(web-mode-variable-name-face
   ((t :inherit font-lock-variable-name-face)))
 '(web-mode-function-call-face
   ((t :inherit font-lock-function-name-face)))
 '(web-mode-function-name-face
   ((t :inherit font-lock-function-name-face)))
 '(web-mode-warning-face
   ((t :inherit font-lock-warning-face)))
 '(web-mode-css-color-face
   ((t :inherit font-lock-reference-face)))
 '(web-mode-css-rule-face
   ((t :inherit font-lock-function-name-face)))
 '(web-mode-css-pseudo-class-face
   ((t :inherit font-lock-function-name-face)))
 '(web-mode-css-at-rule-face
   ((t :inherit font-lock-keyword-face))))

説明

web-modeの有効化

まず,以下の設定によって.jsxもしくは.tsxのファイルを開いたときweb-modeを有効にしています.

(add-to-list 'auto-mode-alist '("\\.[jt]sx\\'" . web-mode))

インデントの設定

以下はインデントの設定です.rjsx-modeと近く※ なるように,JSXのみインデント幅が小さくなるように設定しています.

(※ あなたのEmacsでは,rjsx-modeのインデント幅が違うかもしれません)

  (setq web-mode-attr-indent-offset nil)
  (setq web-mode-markup-indent-offset 2)
  (setq web-mode-css-indent-offset 4)
  (setq web-mode-code-indent-offset 4)
  (setq indent-tabs-mode nil)
  (setq tab-width 2)

対応するタグをハイライトする設定

以下は,JSXを編集する際に対応するタグをハイライトするための設定です.ハイライトされる色 (face) は,web-mode-current-element-highlight-faceです.最後に他の色と合わせて設定しています.

  (setq web-mode-enable-current-element-highlight t)

型をハイライトする設定

以下は,Typescriptの型をハイライトするための設定です.正規表現の部分を編集することで,ハイライトする型を増やすことができます.ハイライトされる色 (face) は,font-lock-type-faceとしています.

なお,バッファ内で一致した単語をすべてハイライトするため,コメントに含まれるものなどであってもハイライトされます.ただし,case-fold-searchをセットしていることから,大文字・小文字は区別されます.

  (let ((case-fold-search nil))
    (highlight-regexp "\\_<number\\|string\\|boolean\\|enum\\|unknown\\|any\\|void\\|null\\|undefined\\|never\\|object\\|symbol\\_>" 'font-lock-type-face))

カラーテーマを(おおむね)適用する設定

以下は,使用中のカラーテーマの色(正確には,font-lockの色)をおおむね適用するための設定です.web-modeが定義する色 (face) の一部を,font-lockが定義する色 (face) に書き換えています.

なお,web-modefont-lockが定義する色 (face) は,M-x list-faces-displayで確認することができます.また,バッファ中のカーソルがある部分の色 (face) は,C-u C-x =で確認することができます.これらの情報は,以下の設定を変更する上で,とても役に立つでしょう.

(custom-set-faces
 '(web-mode-doctype-face
   ((t :inherit font-lock-doc-face)))
 '(web-mode-html-tag-face
   ((t :inherit font-lock-function-name-face)))
 '(web-mode-html-attr-name-face
   ((t :inherit font-lock-variable-name-face)))
 '(web-mode-html-attr-value-face
   ((t :inherit font-lock-string-face)))
 '(web-mode-comment-face
   ((t :inherit font-lock-comment-face)))
 '(web-mode-server-comment-face
   ((t :inherit font-lock-comment-face)))
 '(web-mode-javascript-comment-face
   ((t :inherit font-lock-comment-face)))
 '(web-mode-json-comment-face
   ((t :inherit font-lock-comment-face)))
 '(web-mode-error-face
   ((t :inherit font-lock-warning-face)))
 '(web-mode-current-element-highlight-face
   ((t :inherit font-lock-builtin-face)))
 '(web-mode-html-tag-bracket-face
   ((t :inherit font-lock-negation-char-face)))
 '(web-mode-block-delimiter-face
   ((t :inherit font-lock-negation-char-face)))
 '(web-mode-javascript-string-face
   ((t :inherit font-lock-string-face)))
 '(web-mode-json-key-face
   ((t :inherit font-lock-keyword-face)))
 '(web-mode-json-string-face
   ((t :inherit font-lock-string-face)))
 '(web-mode-keyword-face
   ((t :inherit font-lock-keyword-face)))
 '(web-mode-param-name-face
   ((t :inherit font-lock-variable-name-face)))
 '(web-mode-preprocessor-face
   ((t :inherit font-lock-preprocessor-face)))
 '(web-mode-string-face
   ((t :inherit font-lock-string-face)))
 '(web-mode-type-face
   ((t :inherit font-lock-type-face)))
 '(web-mode-variable-name-face
   ((t :inherit font-lock-variable-name-face)))
 '(web-mode-function-call-face
   ((t :inherit font-lock-function-name-face)))
 '(web-mode-function-name-face
   ((t :inherit font-lock-function-name-face)))
 '(web-mode-warning-face
   ((t :inherit font-lock-warning-face)))
 '(web-mode-css-color-face
   ((t :inherit font-lock-reference-face)))
 '(web-mode-css-rule-face
   ((t :inherit font-lock-function-name-face)))
 '(web-mode-css-pseudo-class-face
   ((t :inherit font-lock-function-name-face)))
 '(web-mode-css-at-rule-face
   ((t :inherit font-lock-keyword-face))))
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Gatsby + Netlifyで静的サイトをつまづきながら1時間で立ち上げる

Gatsby.jsの Quick Start をつまづきながら進めました。
5分~10分程度で試せる想定が1時間ほどかかりました。。
進めるにあたり GatsbyとNetlifyで簡単にブログを作成 を参考にさせていただきました。

0. 環境

  • Windows 10
  • 各操作はVSCodeのコンソールから行っています。
  • Netlify のアカウントを用意する必要があります。

1. Gatsby CLIをインストールする

$ npm install -g gatsby-cli

既にインストール済みであればパッチが当たります。

   ╭────────────────────────────────────────────────────────────────╮
   │                                                                │
   │      New patch version of npm available! 6.14.6 -> 6.14.8      │
   │   Changelog: https://github.com/npm/cli/releases/tag/v6.14.8   │
   │               Run npm install -g npm to update!                │
   │                                                                │
   ╰────────────────────────────────────────────────────────────────╯

2. プロジェクトを作成する

こちらからサンプルを選びます。
今回はポートフォリオのサンプルを選択しました。

sample.png

サンプルコマンドが書いてあるのでコピーしてコンソールへ移動します。
installcommand.png

実行すると早速セキュリティエラーが出ました。

$ gatsby new gatsby-starter-portfolio-cara https://github.com/LekoArts/gatsby-starter-portfolio-cara
gatsby : このシステムではスクリプトの実行が無効になっているため、ファイル XXX\gatsby.ps1 を読み込むことができません。詳細については、「about_Execution_Policies」(https://go.micros
oft.com/fwlink/?LinkID=135170) を参照してください。
発生場所 行:1 文字:1
+ gatsby new gatsby-starter-portfolio-cara https://github.com/LekoArts/gatsby-starter-portfol ...
+ ~~~~~~
    + CategoryInfo          : セキュリティ エラー: (: ) []、PSSecurityException
    + FullyQualifiedErrorId : UnauthorizedAccess

以下の記事で対処法を確認します。
PowerShell のスクリプトが実行できない場合の対処方法

引用:
PowerShell のスクリプトの実行が実行ポリシーによって許可されていないことが原因

実行ポリシーを確認します。

$ Get-ExecutionPolicy
Restricted

制限されているので、記事にある恒久的対処法を実施します。

$ Set-ExecutionPolicy RemoteSigned
Set-ExecutionPolicy : レジストリ キー 'HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\PowerShell\1\ShellIds\Microsoft.PowerShell' へのアクセスが拒否されました。 既定 (LocalMachine) のスコープの実行ポリシーを変更するに
は、[管理者として実行] オプションを使用して Windows PowerShell を起動してください。現在のユーザーの実行ポリシーを変更するには、"Set-ExecutionPolicy -Scope CurrentUser" を実行してください。
発生場所 行:1 文字:2
+  Set-ExecutionPolicy RemoteSigned
+  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : PermissionDenied: (:) [Set-ExecutionPolicy], UnauthorizedAccessException
    + FullyQualifiedErrorId : System.UnauthorizedAccessException,Microsoft.PowerShell.Commands.SetExecutionPolicyCommand

PowerShellに管理者権限がないようです。
以下の記事で対処法を確認しました。
PowerShell スクリプトの実行が無効となっている場合の対処法

引用:
現在のユーザーに関しての権限がある場合は以下のように-Scope CurrentUserオプションを付与すると実行できる場合もある。

VSCodeからPowerShellを管理者権限で起動する方法がわからなかったので、-Scope CurrentUser オプションで実行してみます。

$ Set-ExecutionPolicy -Scope currentUser RemoteSigned

エラーや成功などは出ませんが、実行ポリシーは変更できていました。

$ Get-ExecutionPolicy
RemoteSigned

再度プロジェクトを作成します。

$ gatsby new gatsby-starter-portfolio-cara https://github.com/LekoArts/gatsby-starter-portfolio-cara
info Creating new site from git: https://github.com/LekoArts/gatsby-starter-portfolio-cara.git
Cloning into 'gatsby-starter-portfolio-cara'...
remote: Enumerating objects: 25, done.
remote: Counting objects: 100% (25/25), done.

:

Your new Gatsby site has been successfully bootstrapped. Start developing it by running:

  cd gatsby-starter-portfolio-cara
  gatsby develop

成功しました。

3. ローカルで起動する

$ cd gatsby-starter-portfolio-cara
$ gatsby develop
success open and validate gatsby-configs - 0.017s
success load plugins - 0.163s

:

You can now view cara in the browser.
⠀
  http://localhost:8000/
⠀
View GraphiQL, an in-browser IDE, to explore your site's data and schema
⠀
  http://localhost:8000/___graphql
⠀
Note that the development build is not optimized.
To create a production build, use gatsby build
⠀
success Building development bundle - 12.159s

ブラウザから http://localhost:8000/ へアクセスします。

site.png

GraphQL へもアクセスしてみます。 http://localhost:8000/___graphql
アクセスできました。

graphql.png

GraphQLはFacebookが開発しているクエリ言語とのこと。
これは追々勉強しようと思います。

4. GitHubへプッシュする

先にGitHub上でリポジトリを作っておきます。
createrepository.png

リポジトリが出来たらURLをコピーしておきます。
url.png

コンソールへ戻ります。

ローカルでは既にコミットされた状態です。git logで確認します。

$ git log
commit 0ba88f461cd6a584b1fb27e7bd49b675af3f2345 (HEAD -> master)
Author: k <XXXXX@XXXXX>
Date:   Thu Sep 10 20:38:44 2020 +0900

    Initial commit from gatsby: (https://github.com/LekoArts/gatsby-starter-portfolio-cara.git)

リモートリポジトリを追加します。

$ git remote add origin https://github.com/kyonc5/gatsby-starter-test.git

pushします。

$ git push origin master  

5. Netlifyへデプロイする

Netlifyを開きNew site from Gitを押します。
newsite.png

GitHubを押します。
connecttogit.png

リポジトリを選択します。
selectrepo.png

Deploy siteを押します。
deploysite.png

deployされるのを待ちます。
progress.png

完了すると以下の状態になります。

published.png

表示されたURLへアクセスします。

access.png

アクセスできました。これで完了です。

6. サイトを更新する

画面を編集してみます。
選んだサンプルによってファイルが違いますが、今回はintro.mdxファイルを更新します。

# Hi, I'm Jane Doe

# Hi, I'm kyonc5

commit、pushします。

$ git add .
$ git commit -m "update name"
$ git push origin master

自動でデプロイされページが更新されます。

updatesite.png

出来たページはこちらです。

参考

以下参考にさせていただきました。ありがとうございました。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

[MERN⑤] Getting Started With React & The Frontend

~~~~~~~~~~ (Contents) MERN ~~~~~~~~~~~
[MERN①] Express & MongoDB Setup
https://qiita.com/niyomong/private/3281af84486876f897f7
[MERN②]User API Routes & JWT Authentication
https://qiita.com/niyomong/private/c11616ff7b64925f9a2b
[MERN③] Profile API Routes
https://qiita.com/niyomong/private/8cff4e6fa0e81b92cb49
[MERN④] Post API
https://qiita.com/niyomong/private/3ce66f15375ad04b8989
[MERN⑤] Getting Started With React & The Frontend
https://qiita.com/niyomong/private/a5759e2fb89c9f222b6b
[MERN⑥] Redux Setup & Alerts
https://qiita.com/niyomong/private/074c27259924c7fd306b
[MERN⑦] React User Authentication
https://qiita.com/niyomong/private/37151784671eff3b92b6
[MERN⑧] Dashboard & Profile Management
https://qiita.com/niyomong/private/ab7e5da1b1983a226aca
[MERN⑨] Profile Display
https://qiita.com/niyomong/private/42426135e959c7844dcb
[MERN⑩] Posts & Comments
https://qiita.com/niyomong/private/19c78aea482b734c3cf5
[MERN11] デプロイ
https://qiita.com/niyomong/private/150f9000ce51548134ad
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

1. React & Concurrently Setup

1.1 reactフォルダを作成 (例)フォルダ名-> client

$ npx create-react-app client

1.2 package.jsonに同時起動するように下記追加。

package.json
{
...
  "scripts": {
    "start": "node server",
    "server": "nodemon server",
+    "client": "npm start --prefix client",
+    "dev": "concurrently \"npm run server\" \"npm run client\""
  },
 ...
  "devDependencies": {
    "concurrently": "^5.3.0",
    "nodemon": "^2.0.4"
  }
}

・「---prefix client」:clientフォルダ内のファイルっていう意味
・concurrently \"起動したいサーバー①\" \"起動したいサーバー②\""

1.3 ExpressとReactを両方同時に起動する。

$ npm run dev

1.4 ライブラリ(Dependencies)をインストール

$ npm i axios react-router-dom redux react-redux redux-thunk redux-devtools-extension moment react-moment
~~ 補足説明 ~~
省略。

1.5 axiosで毎回「http://xxx」の記述を省略したい

-> axios.get(http://xxx/api/xx)ではなく、axios.get(/api/xx)に省略する

app/client/package.json
...
    "development": [
      "last 1 chrome version",
      "last 1 firefox version",
      "last 1 safari version"
    ]
  },
+  "proxy": "http://localhost:5000"
}

2. Clean Up & Initial Components

2.1 (create-react-appでデフォルトで生成される)不要なファイルを削除

$ rm .gitignore README.md
$ rm -rf .git
$ rm src/App.test.js src/index.css src/logo.svg src/serviceWorker.js src/setupTests.js

-> index.jsとApp.jsで上記で削除したファイルのimport等を削除する
-> App.cssファイルの中身すべて削除
-> App.jsの中身を下記の通り整理する。
【ここ確認!】「const App = () =>」はHooks使ってる?

client/src/App.js
import React, { Fragment } from 'react';
import './App.css';

const App = () => (
  <Fragment>
    <h1>App</h1>
  </Fragment>
);

export default App;

2.2 Fontawesomeを設置

https://fontawesome.com/

client/public/index.html
<!DOCTYPE html>
<html lang="en">
  <head>
...
    <link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" />
+    <script src="https://kit.fontawesome.com/ce63691a5a.js" crossorigin="anonymous"></script>
    <link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
    <title>XXXXX</title>
  </head>

2.3 layout関連ファイル作成

mkdir src/img
mkdir src/components
mkdir src/components/layout
touch src/components/layout/Navbar.js
touch src/components/layout/Landing.js

① racfe -> 「Enter」で以下記述される。

Navbar.js
import React from 'react'

export const Navbar = () => {
  return (
    <div></div>
  )
}

② 上記のNavbar.jsにNavbarのテーマを

のところに挿入。
サンプル.html
    <nav class="navbar bg-dark">
      <h1>
        <a href="index.html"><i class="fas fa-code"></i> DevConnector</a>
      </h1>
      <ul>
        <li><a href="profiles.html">Developers</a></li>
        <li><a href="register.html">Register</a></li>
        <li><a href="login.html">Login</a></li>
      </ul>
    </nav>

③ class -> classNameに変える(React仕様)

src/components/layout/Layout.js
import React from 'react';

const Navbar = () => {
  return (
    <nav className="navbar bg-dark">
      <h1>
        <a href="index.html"><i className="fas fa-code"></i> サービス名</a>
      </h1>
      <ul>
        <li><a href="profiles.html">Developers</a></li>
        <li><a href="register.html">Register</a></li>
        <li><a href="login.html">Login</a></li>
      </ul>
    </nav>
  );
};

export default Navbar;

④ Landing.jsも同じようにLandingテーマを

のところに挿入、classNameに置き換える。

⑤ App.jsにNavbarとLandingを設置。

src/App.js
import React, { Fragment } from 'react';
+ import Navbar from './components/layout/Navbar';
+ import Landing from './components/layout/Landing';
import './App.css';

const App = () => (
  <Fragment>
+    <Navbar />
+    <Landing />
  </Fragment>
);

export default App;

3. React Router Setup

①src/components/authフォルダにLogin.jsとRegister.jsを生成
-> 「racfe」

② React Routerを設置

src/App.js
import React, { Fragment } from 'react';
+ import { BrowserRouter as Router, Route, Switch } from 'react-router-dom';
import Navbar from './components/layout/Navbar';
import Landing from './components/layout/Landing';
+ import Register from './components/auth/Register';
+ import Login from './components/auth/Login';
import './App.css';

const App = () => (
+   <Router>
    <Fragment>
      <Navbar />
+       <Route exact path="/" component={Landing} />
+       <section className="container">
+         <Switch>
+           <Route exact path="/register" component={Register} />
+           <Route exact path="/login" component={Login} />
+         </Switch>
+       </section>
    </Fragment>
+   </Router>
);

export default App;

src/components/layout/navbar.js
//① import { Link } from 'react-router-dom';
//② <a href="!#">xxx</a> を <Link to="/xxx"></Link> に変える。

import React from 'react';
+ import { Link } from 'react-router-dom';

const Navbar = () => {
  return (
    <nav className="navbar bg-dark">
      <h1>
+         <Link to="/"><i className="fas fa-code"></i> RefNote</Link>
      </h1>
      <ul>
        <li><a href="#!">Developers</a></li>
+        <li><Link to="/register">Register</Link></li>
+        <li><Link to="/login">Login</Link></li>
      </ul>
    </nav>
  );
};

export default Navbar;

4. Register 「Form」 & useState Hook

4.1 HTML記述をで囲む
4.2 入力蘭それぞれ「state」と「changeハンドラー」を持たせる。 ->「state」をUpdateするため。
4.2A「useState(Hooks)」を使う!!!

hooksSample.js
////通常の書き方////
//①formDataに該当する書き方
  state = {
    formData: {
      name: '', email: '', password: '', password2: '',
    },
  };
//②setFormDataに該当する書き方
  this.setState
↓↓↓↓↓↓
////Hooks////
  const [formData, setFormData] = useState({
      name: '', email: '', password: '', password2: '',
  });
//【説明】
//①formData(オブジェクト)②setFormData(関数)をuseState({オブジェクトs})に格納する。

4.2B onChangeハンドラーの分離(要はreturn後で直接記述せずreturnの前で定義する)

SamleChangeHandler.js
const onChange = (e) => setFormData({ ...formData, [e.target.name]: e.target.value });
//③ {...オブジェクト名} は「Spread Attributes」と呼ばれる。
//指定したオブジェクト名でオブジェクトのプロパティをまとめて下の階層に渡せる。
//オブジェクトのプロパティを追加したり削除したりするときに、コンポーネントのオブジェクトをいじる必要がなくなる。
//④「nameをkeyとして」データを渡しているが、[e.target.name]だといかなるname keyでも対応できる。

(参考)Spread Attributes「...」 https://mae.chab.in/archives/2897

src/components/auth/Register.js
import React, { Fragment, useState } from 'react';

const Register = () => {
  const [formData, setFormData] = useState({
    name: '',
    email: '',
    password: '',
    password2: '',
  });

  const { name, email, password, password2 } = formData;

  const onChange = (e) =>
    setFormData({ ...formData, [e.target.name]: e.target.value });

  const onSubmit = (e) => {
    e.preventDefault();
    if (password !== password2) {
      console.log('Passwords do not match');
    } else {
      console.log('SUCCESS');
    }
  };

  return (
    <Fragment>
      <h1 className="large text-primary">Sign Up</h1>
      <p className="lead">
        <i className="fas fa -user"></i> Create Your Account
      </p>
+      <form className="form" onSubmit={(e) => onSubmit(e)}>
        <div className="form-group">
          <input
            type="text"
            placeholder="Name"
            name="name"
+            value={name}
+            onChange={(e) => onChange(e)}
            required
          />
        </div>
        <div className="form-group">
          <input
            type="email"
            placeholder="Email Address"
            name="email"
            value={email}
            onChange={(e) => onChange(e)}
            required
          />
          <small className="form-text">
            This site uses Gravatar so if you want a profile image, use a
            Gravatar email
          </small>
        </div>
        <div className="form-group">
          <input
            type="password"
            placeholder="Password"
            name="password"
            value={password}
            onChange={(e) => onChange(e)}
            minLength="6"
          />
        </div>
        <div className="form-group">
          <input
            type="password"
            placeholder="Confirm Password"
            name="password2"
            value={password2}
            onChange={(e) => onChange(e)}
            minLength="6"
          />
        </div>
        <input type="submit" className="btn btn-primary" value="Register" />
      </form>
      <p className="my-1">
        Already have an account? <a href="login.html">Sign In</a>
      </p>
    </Fragment>
  );
};

export default Register;

4. Login Form

-> Register.jsを同じ。
(不要なInputsは削除。例えばname等)

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む