- 投稿日:2020-06-25T22:36:59+09:00
Docker TypeScript で React 環境を構築
自分用のmemoのつもりで
Dockerで環境構築
Dockerはinstall済み■Dockerfile作成
空のPJディレクトリ内にDokerfile作成し以下を記載FROM node:13.5.0-alpine3.11 WORKDIR /usr/src/appFROMは新しいイメージの元となるイメージの読み込み
alpineというのでめちゃくちゃファイルサイズを小さくできるらしい■docker-compose.yml作成
※ymlは「yaml ain't markup language」の略で構造化データの表現方法
※簡単に言えば設定ファイルversion: '3' services: sample: build: context: . tty: true environment: - NODE_ENV=production volumes: - ./:/usr/src/app command: sh -c "cd tips && yarn start" ports: - "3000:3000"■イメージをビルド
docker-compose build■React と create-react-app をインストール + アプリ作成
docker-compose run --rm sample sh -c 'npx create-react-app sample_app --template typescript'出来上がるディレクトリ 構成
- Dockerfile - docker-compose.yml - アプリ名 |- node_module |- public |- src■起動
docker-compose up -d※ローカルでyarn startする時よりも時間がかかる感覚はある
Localhost:3000でApp.jsの中身が表示される
■停止
docker-compose stop
- 投稿日:2020-06-25T21:05:13+09:00
僕が考えた最強の React 技術スタック
開発
フレームワーク
- Next.js
$ npx create-next-app
with-typescript-eslint-jest
を選択すると、いい感じに色々入る状態管理
フォーム
コンポーネントフレームワーク
HTTP クライアント
Firebase
ユニットテスト
開発補助
スタイルガイド
- Storybook
$ npx -p @storybook/cli sb init --type react
Linter
- ESLint
$ npx eslint --init
- eslint-plugin-react
- eslint-plugin-react-hooks
- eslint-plugin-jsx-a11y
- eslint-config-airbnb
- lint-staged
$ npx mrm lint-staged
Formatter
環境変数
気になってる
- 投稿日:2020-06-25T15:27:30+09:00
[1行で完了]最速でReact環境構築
※自分のアウトプット用(メモ)です
結論だけ知りたい人用
1行のコマンドで
React
の環境構築を完了する。
[条件]
1.Node.js 8.10以上
2.npm 5.6以上$ npx create-react-app プロジェクト名
順番通り説明していきます。
必要なパッケージのインストール方法
1.
brew
をインストールMacのパッケージ管理システムであるbrewをインストール。
brew公式サイト$ /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install.sh)"2.
nodebrew
をbrew
でインストールnodeのバージョン管理ができるnodebrewをインストール。
(brewでインストールするので先にbrewをインストールした)。$ brew install nodebrew3.
Node.js
をnodebrew
を使ってインストールNode.jsはnodebrewで管理した方が使いやすいと思います。他のバージョンに移るの簡単ですし、普通にインストールすると削除するのに手間なんですよね...
ほとんどの場合、安定版をインストールしておけば問題ないと思います。// リモートにあるインストールできるNode.jsの一覧表示 $ nodebrew ls-remote // 安定版をローカル(自分のMac)にインストール $ nodebrew install stable // ローカルにインストールされている`Node.js`のバージョンを一覧表示 $ nodebrew ls // インストールしたバージョンの`Node.js`を選択する $ nodebrew use 使用したいバージョン番号4.
Node.js
のパスを通す// "~/.bash_profile"にパスを追記する(bashの場合) $ echo 'export PATH=$HOME/.nodebrew/current/bin:$PATH' >> ~/.bash_profile // ターミナルを再起動して反映 // または以下を実行して反映 $ source ~/.bash_profile5.
node
とnpm
が使用可能か確認Node.jsをインストールした時点でnpm(node package manager)もインストールされているので、うまくいっていればこの時点で使用可能になっているはずです。
// Node.js $ node -v // npm $ npm -vこれで準備は整いました。
create-react-app
でReact
の環境構築任意の場所で以下のコマンドを叩いてください。
npx
コマンドを簡潔に説明すると、パッケージをローカルにインストールすることなく実行できるコマンドです。
環境を汚染しないので手軽に実行して見たいときに便利です。
詳細はこちら。$npx create-react-app プロジェクト名
これでカレントディレクトリにreactのプロジェクトが作成されました。
以下のコマンドでブラウザ表示します。$ npm start
お疲れ様でした。
- 投稿日:2020-06-25T14:17:53+09:00
React Hooksを使ったモーダル実装
React HooksのuseState・useRefを使ったモーダル実装についてまとめました。
今回実装するのは、以下のようなモーダルになります。
完成コード
React
import React, {useState, useRef} from 'react'; const App = () => { const [modal, setModal] = useState(false) const modalRef = useRef() return ( <div> <button onClick={() => setModal(true)}>Open</button> <div className={`modal__overlay ${modal && "is-opened"}`} onClick={e=>{if(modalRef.current === e.target) setModal(false)}} ref={modalRef}> <div className="modal__box"> <button className="modal__closeBtn" onClick={() => setModal(false)}>×</button> <div>モーダルテキスト</div> </div> </div> </div> ); } export default App;CSS
.modal__overlay{ position: fixed; top: 0; left: 0; width: 100vw; height: 100vh; background: rgba(0,0,0,0.4); z-index: 999; display: flex; align-items: center; justify-content: center; opacity: 0; visibility: hidden; transition: opacity .3s, visibility .3s; } .is-opened{ visibility: visible; opacity: 1; } .modal__box{ background-color: #fff; position: relative; padding: 30px 20px; } .modal__closeBtn{ position: absolute; top: 0; right: 0; }実装流れ
1.モーダルの見た目作成
まず、オーバーレイ要素(画面全体を覆う薄暗い要素)とモーダルボックスを作成します。
import React from 'react'; const App = () => { return ( <div> {/* オーバーレイ要素でモーダルボックスを囲む */} <div className="modal__overlay"> <div className="modal__box"> <div>モーダルテキスト</div> </div> </div> </div> ); } export default App;.modal__overlay{ /* 画面全体を覆う設定 */ position: fixed; top: 0; left: 0; width: 100vw; height: 100vh; background: rgba(0,0,0,0.4); z-index: 999; /* 画面中央にモーダルを表示させる設定 */ display: flex; align-items: center; justify-content: center; } .modal__box{ background-color: #fff; padding: 30px 20px; }2.モーダルの表示切り替えの実装
次に、ボタンクリックでモーダルの表示・非表示を切り替えます。
// useState追加 import React, {useState} from 'react'; const App = () => { // モーダルの表示・非表示をstate管理(true:表示 false:非表示) // ※modal:現在のstate値 setModal:state値を更新するための関数 false:初期値 const [modal, setModal] = useState(false) return ( <div> {/* ボタンクリック後、modalをtrueに変更 */} <button onClick={() => setModal(true)}>Open</button> {/* modalがtrueの場合、is-openedクラスを付与 */} <div className={`modal__overlay ${modal && "is-opened"}`}> <div className="modal__box"> {/* ボタンクリック後、modalをfalseに変更 */} <button className="modal__closeBtn" onClick={() => setModal(false)}>×</button> <div>モーダルテキスト</div> </div> </div> </div> ); }.modal__overlay{ z-index: 999; position: fixed; top: 0; left: 0; width: 100vw; height: 100vh; background: rgba(0,0,0,0.4); display: flex; align-items: center; justify-content: center; /* 初期状態は非表示 */ opacity: 0; visibility: hidden; /* ゆっくり表示させる */ transition: opacity .3s, visibility .3s; } /* モーダル表示(modalがtrueになったら付与される) */ .is-opened{ visibility: visible; opacity: 1; } .modal__box{ background-color: #fff; padding: 30px 20px; position: relative; } .modal__closeBtn{ position: absolute; top: 0; right: 0; }3.オーバーレイクリックでモーダルを閉じる処理
最後に、オーバーレイをクリックした時にもモーダルを閉じるようにしたいと思います。
<div className={`modal__overlay ${modal && "is-opened"}`} onClick={() => setModal(false)}>このように追記することで、オーバーレイクリック後にモーダルを閉じることができますが、これだとモーダルボックス内をクリックした時にも閉じてしまいます。
そこで、コンポーネントのDOMノードに直接アクセスできるようになるuseRefフックを使用します。// useRef追加 import React, {useState, useRef} from 'react'; const App = () => { // modalRefの定義 ※modalRef.currentでオーバーレイ要素を取得可能に const modalRef = useRef() const [modal, setModal] = useState(false) return ( <div> <button onClick={() => setModal(true)}>Open</button> {/* クリックした要素がmodalRef.currentと一致した場合、modalをfalseに変更 */} <div className={`modal__overlay ${modal && "is-opened"}`} onClick={e=>{if(modalRef.current === e.target) setModal(false)}} ref={modalRef}> <div className="modal__box"> <button className="modal__closeBtn" onClick={() => setModal(false)}>×</button> <div>モーダルテキスト</div> </div> </div> </div> ); } export default App;完成
このようにuseState・useRefを使用することで簡単にモーダル実装ができますので、是非お試し下さい!
参考文献
https://chaika.hatenablog.com/entry/2019/12/08/090000
https://ichiki.netlify.app/blog/20191218_react_click_out/
- 投稿日:2020-06-25T13:08:40+09:00
AdonisJSとReactを使ってイベントを管理するためのモダンなWebアプリを構築する
このチュートリアルでは、ReactとAdonis Node.jsフレームワークを使って、Alibaba Cloud上でREST APIのバックエンドとフロントエンドを構築します。
本ブログは英語版からの翻訳です。オリジナルはこちらからご確認いただけます。一部機械翻訳を使用しております。翻訳の間違いがありましたら、ご指摘いただけると幸いです。
序章
Adonisは、スケーラブルで安定した効率的なWebアプリケーションやREST APIを構築するために使用できるNode.jsフレームワークです。Reactを使用して、Adonisで構築されたREST APIを消費するためのモダンで堅牢なフロントエンドWebアプリケーションを構築します。
これから構築するWebアプリケーションは、MySQLのデータベースにイベントを格納し、これらのイベントを読み込んで削除します。
完成したら、以下のことができるようになります。
- Adonis.jsを使ったREST APIの構築
- Reactを使ってREST APIを消費する堅牢なクライアントサイドアプリケーションを構築する
- Bootstrap 4とReactを統合する
前提条件
このガイドを始める前に、以下のものが必要です。
- Ubuntu 18.04を搭載したElastic Compute Service (ECS)開発マシン。
- Node.js 8.0.0.0+とNpm 3.0.0.0+がマシンにインストールされている。
- ローカルにインストールされたMySQL 5.7+。
ステップ1 - Adonis APIプロジェクトの作成と依存関係のインストール
このステップでは、Adonisプロジェクトを足場にするのに役立つAdonis CLIをインストールし、アプリケーションのデータベース接続をセットアップするために必要な依存関係をインストールします。
ターミナルを開き、以下のコマンドを実行してAdonis.js CLIをグローバルにインストールします。
npm i -g @adonisjs/cliこれでインストールが完了したら、ターミナルのどこからでも
adonis
を実行できるようになるはずです。以下のコマンドを実行して、インストールしたCLIのバージョンを確認することで試すことができます。adonis --version次に、新しいAdonisアプリケーションを足場にする必要があります。任意のディレクトリに移動し、以下のコマンドを実行します。
adonis new adonis-events --api-only新しいコマンドは
adonis-events
という新しいプロジェクトを足場にし、--api-only
は生成されたプロジェクトが特に REST API 用であることを指定します。新しいコマンドは、新しいプロジェクトに必要なすべての npm 依存関係をインストールします。生成されるプロジェクトは以下のような構造になっているはずです。
次に、データベース接続を設定する必要があります。Adonis は多くの SQL データベースをサポートしていますが、使用する特定のデータベース、この場合は MySQL 用のパッケージをインストールする必要があります。プロジェクトフォルダに移動し、以下のコマンドを実行します。
npm i --save mysqlこのプロジェクトでは、
.env
というファイルにアプリケーションを設定するための環境変数が含まれています。データベース接続がmysql
に設定されていることを確認してください。[~/adonis-events/.env] ... DB_CONNECTION=mysql ...最後に、このプロジェクトで使用する MySQL データベースをローカルに作成する必要があります。ローカルにMySQLがインストールされている場合は、以下のコマンドを実行してデータベースを作成します。
mysql -u rootmysql> CREATE DATABASE events;新しいデータベースを作成したら、
.env
ファイルの資格情報を作成したデータベースと一致するように更新します。[~/adonis-events/.env] ... DB_CONNECTION=mysql DB_USERNAME=root DB_DATABASE=events DB_PASSWORD= ...これが完了したら、REST APIとReactフロントエンドの作成に進みます。
ステップ2 - Reactフロントエンドを作成する
このステップでは、Reactを使ってアプリケーションのフロントエンドを作成します。webpack の設定や本番のビルドプロセスを気にすることなく、React アプリケーションを素早く足場にするために、
crease-react-app
という人気のあるパッケージを使用します。ローカルにcreate-react-app
がインストールされていない場合は、以下のコマンドを実行してください。npm i -g create-react-appインストールしたら、新しいフォルダに移動し、以下のコマンドを実行して新しいReactプロジェクトを作成します。
create-react-app adonis-events-react新たに生成されたReactプロジェクトの構造は以下のようになります。
新しく作成したReactプロジェクトを起動するには、Reactプロジェクトディレクトリに移動し、以下のコマンドを実行します。
npm startこれにより開発サーバーが起動し、デフォルトのブラウザで以下のようなReactアプリケーションが開くはずです。
最後に、基本的なスタイリングを行うためのBootstrap CSSフレームワークをインストールしてみましょう。
Reactプロジェクト内の
src
フォルダに入り、index.css
ファイルを開きます。このファイルの内容を以下のように置き換えます。[~/adonis-events-react/src/index.css] @import 'https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css';上記は、ブートストラップCSSファイルへのリンクをインポートしたもので、フロントエンドプロジェクトのスタイルを素早く設定するために使用できるすべてのスタイルとクラスが含まれています。
フロントエンドアプリケーションのセットアップが完了したので、データベースモデルと移行を開発しましょう。
ステップ3 - イベントの移行とモデルの作成
このステップでは、データベーステーブルをどのように構造化するかを決定する移行をセットアップし、このデータベーステーブルとの対話に役立つモデルをセットアップします。
まず、ターミナルでAdonisアプリケーションに移動し、次のコマンドを実行します。
adonis make:model Event -mこのコマンドは、モデルとそれに対応するマイグレーションを素早く作成する方法です。以下のような出力が得られます。
create app/Models/Event.js create database/migrations/1541120387036_event_schema.js作成したファイルは2つで、
app/Models/Event.js
はこんな感じです。'use strict' const Model = use('Model') class Event extends Model { } module.exports = Eventこれは基本的なES6のクラスで、ベースとなる
Model
クラスを継承しています。見ての通り、このクラスには多くの静的メソッドがあり、データベースと簡単にやりとりするのに役立ちます。2つ目のファイルは、
database/migrations/1541120387036_event_schema.js
で、以下のようになっています。'use strict' const Schema = use('Schema') class EventSchema extends Schema { up () { this.create('events', (table) => { table.increments() table.timestamps() }) } down () { this.drop('events') } } module.exports = EventSchemaAdonisのマイグレーションは、ベースの
Schema
クラスを拡張したES6クラスで、2つの重要なメソッドを含んでいます:up
は、データベーステーブルの作成や変更を含むデータベースへの変更を行うために使用され、down
はそれらの変更を反転させるために使用されます。up
関数では、データベーステーブルの構造を記述するAdonisが提供するメソッドを呼び出します。現時点では、
up
関数の中の関数this.create('events')がデータベース内にイベントテーブルを作成します。また、down
関数のthis.drop('events’)
は、必要に応じてデータベース内のイベントテーブルを削除します。イベントテーブルには以下のフィールドがあります。
- title - イベントのタイトル
- start_date - イベントの開始日.
- end_date - イベントの終了日.
- location - 偶数の場所
- price - イベントの費用
マイグレーションでは、以下のようにこれらのフィールドを定義します。
次に、このマイグレーションファイルを実行して、Adonisが接続されたデータベースにこれらの変更を影響させることができるようにする必要があります。
プロジェクトフォルダにあることを確認し、以下のコマンドを実行してください。
adonis migration:run以下のような出力が表示されるはずです。
migrate: 1503250034279_user.js migrate: 1503250034280_token.js migrate: 1541120387036_event_schema.js Database migrated successfully in 206 msこのコマンドを実行すると、Adonisは各マイグレーションファイルを読み込み、これらのファイル内で
up
機能を実行します。したがって、現時点では、私たちのデータベースには、users
、tokens
、events
の3つのテーブルが新たに作成されています。最初の2つのテーブルは、Adonisの新規インストール時にデフォルトで出荷されます。データベースのセットアップが完了したら、REST APIの作成に進みます。
ステップ4 - REST APIの作成
このステップでは、REST APIを作成します。イベントに対するさまざまなアクションを処理するために、いくつかの API エンドポイントを作成します。作成するエンドポイントは以下の通りです。
[POST] /api/events
は、イベントを作成[DELETE] /api/events/:id
は、 特定のイベントを削除[GET] /api/events
は、すべてのイベントのリストを取得[POST]/api/eventsエンドポイントの実装
まずは、これらのエンドポイントを処理するためのコントローラを生成することから始めましょう。コントローラは基本的に ES6 クラスで、すべてのビジネスロジックを処理するメソッドを含んでいます。以下のコマンドを実行してください。
adonis make:controller EventController以下のような出力が表示されるはずです。
> Select controller type For HTTP requests create app/Controllers/Http/EventController.js次に、この特定のエンドポイントを扱うルートを登録する必要があります。
start/routes.js
ファイルを開き、以下を追加します。
Route
クラスにはpost
という静的関数があり、このメソッドはpostエンドポイントを登録します。最初のパラメータはパス、api/events
、2番目のパラメータはこのエンドポイントへのリクエストを処理するコントローラとメソッドです。この場合、EventController
のstore
メソッドです。つまり、このメソッドを作成する必要があります。EventController
のように追加します。Adonis は
context
と呼ばれるオブジェクトを注入しますが、このcontext
にはrequest
オブジェクトとresponse
オブジェクトを含む、requestに関する多くの関数とオブジェクトが含まれており、request
オブジェクトにはrequestに関するすべての情報が含まれています。現時点でのstore
メソッドでは、request.all()
関数を呼び出すと、POSTリクエストで送信された全てのデータを返してくれます。今回は、イベントを作成するために、リクエストデータにtitle、start_date、end_date、location、price
が提供されていることを想定しています。次に、このデータをデータベースに保存しなければなりません。データベース、特に
events
テーブルと通信するために、モデルを使用します。events
モデルを使用すると、Adonisは自動的にevents
テーブルに接続します。
events
モデルを使用して、create
関数を呼び出しました。これは、POSTリクエストから取得したデータを使用して、自動的に新しい行をeventsデータベーステーブルに保存します。この関数は新しく作成されたイベントを返し、このeventsと一緒にJSONレスポンスを返します。注: Adonisの
use
関数はNode.jsのrequire
関数のラッパーです。これは名前空間を使用し、上で行ったようにファイルを簡単にrequireするのに役立ちます。ですから、require('../.../.../Models/Event.js’)
の代わりに、単に `use('App/Models/Event') と書きます。先ほど実装した/POSTエンドポイントを試してみましょう。そのためには、Adonis APIを実行する必要があります。
以下のコマンドでadonisサーバーを実行します。
adonis serve --devinfo: serving app on http://127.0.0.1:3333新しく作成したPOST
/api/events
エンドポイントを試すために、任意のRESTクライアントを使用することができます。今回はPOSTMANを使ってみます。操作結果は以下の通りです。
注:POSTMANでは
Content-type
をapplication/json
に設定することを忘れないでください。[取得] api/eventsエンドポイントの実装
このエンドポイントのルートを追加してみましょう。
routes.js
ファイルで、次のように追加します。[~/adonis-events/start/routes.js] Route.get(api/events', 'EventController.index')これはエンドポイントを
EventController
のindex
メソッドにマッピングします。このコントローラでは、次のように追加してみましょう。
index
メソッドは、events
モデルのall()
関数を使用してevents
テーブルからデータベースのすべての行を取得します。これをPOSTMANで試してみると、以下のような結果が得られるはずです。[削除] api/events/:id エンドポイントの実装
最後に実装しなければならないエンドポイントは、イベントを削除するためのものです。このエンドポイントはこれまでの他のエンドポイントとは少し異なり、動的パラメータを使用します。このエンドポイントのルートを登録してみましょう。
[~/adonis-events/start/routes.js] Route.delete(api/events/:id', 'EventController.delete')ルートの
:id
は動的パラメータで、削除したいイベントの特定のid
を渡すことができます。このルートをEventController
のdelete
メソッドにマッチさせます。
delete
メソッドでは、ルートから取得した動的ID
を使用してイベントを検出し、検出されたイベントに対してdelete
関数を呼び出します。以下に POSTMAN でのテストの様子を示します。それだけです。Adonisで完全に機能するAPIを作るのはこんなに簡単なことなのです。フロントエンドに切り替える前にもう一つ。現時点では、Adonis APIは他のサーバーやドメインからのリクエストを許可しません。これはCORS保護と呼ばれるもので、不正なリクエストがAPIに行われないようにするために本当に重要です。この特定のケースでは、ReactフロントエンドがAPIリクエストを行うことを許可するようにAdonisに指示しなければなりません。これを行うには、Adonisには設定ファイルが既に設定されているので、アプリケーションのCORS設定を変更することができます。
config/cors.js
に移動して、このファイルをこのように修正します。[~/adonis-events/config/cors.js] origin: ['http://localhost:3000'],ここでは、すべての認可されたオリジンの配列を作成し、この配列にリストされたすべてのドメインがAdonisアプリケーションにAPIリクエストを行うことができるようになります。クライアント側のReact開発サーバーのドメインは
http://localhost:300
なので、これをorigin
配列に追加しました。次のステップでは、Reactフロントエンドに切り替えて、堅牢なクライアントサイドアプリケーションを構築するために、このデータの消費を開始しましょう。
ステップ5 - クライアントサイドコンポーネントを設定する
最初に設定するコンポーネントは、
App
コンポーネントです。これは、最初にアプリケーションにアクセスしたときに表示されるコンポーネントです。他の不要なファイルもすべてクリーンアップします。不要なファイルを削除した後の現在のフォルダ構造は以下の通りです。
次に、単一のイベントを表現するために使用するコンポーネントを作成してみましょう。プロジェクトフォルダに移動し、
src
フォルダ内にEvent.js
というファイルを作成します。このコンポーネントは、現時点での静的データを表示し、単一のイベントを表示するためのテンプレートを表しています。
最後に、
AddEvent.js
という別のファイルを作成します。これは、新しいイベントを追加するためのフォームとして機能します。必要なコンポーネントの作成が完了したので、APIサービスを作成してみましょう。
ステップ6 - Axios APIサービスの作成
Adonis API と通信できるようにするために、シンプルな HTTP クライアントを使用します。このクライアントをインストールするには、Reactプロジェクトに移動し、次のコマンドを実行します。
npm install axios --saveこれをインストールしたら、
src
フォルダにapiService.js
というファイルを作成し、以下のクラスを追加します。このクラスは axios のシンプルなラッパーであり、Adonis API への HTTP リクエストを行うためのヘルパー関数を提供します。コンストラクタでは、すべてのリクエストの
BaseURL
をAdonisアプリケーションのURLに設定します。サービスの準備ができたので、これらのコンポーネントを機能させてみましょう。
ステップ7 - イベントの作成
イベントを作成するために、
Create Event
ボタンを用意します。ユーザーがこのボタンをクリックすると、イベントを作成するためのフォームを持つコンポーネントが表示されます。Appコンポーネントを以下のように変更してみましょう。現時点では以下のようになっています。
まず、
AddEvent
コンポーネントをインポートしました。showCreateEventForm
というステート・プロパティを設定し、レンダー関数の中で、このプロパティが真であればAddEvent
コンポーネントをマウントし、そうでなければマウントしません。Create Event
ボタンがクリックされると、このステート・プロパティの値を切り替えます。また、showCreateEventForm
がtrue
の場合はCreate Event
ボタンにbtn-danger
クラスを動的に追加し、このプロパティがfalse
の場合はbtn-info
を追加します。次のステップは、このフォームを実際に動作させて、ユーザーがイベントの詳細を入力して保存できるようにすることです。
イベントの作成機能の実装
最初のステップは、ユーザーが入力した入力を取得することです。これを管理するためにステートを使います。ここに
AddEvent.js
コンポーネントのアップデート版があります。この時点では、入力フィールドが変更されるたびに、その値は自動的にこのコンポーネントの状態に設定されます。
現時点では、デフォルトのブラウザの日付ピッカーを使用しており、これには時間ピッカーが統合されていません。さらに、この日付ピッカーの動作はブラウザによって非常に一貫性がありません。そこで、
start_date
とend_date
のフィールドには、FlatPickr
と呼ばれるサードパーティ製の日付ピッカーを使用します。この日付ピッカーをインストールするには、以下のコマンドを実行します。npm i --save react-flatpickrインストールできたら、このようにフォームを修正してみましょう。
まず、インストールした
FlatPickr
コンポーネントをインポートします。前回の日付入力の代わりに、FlatPickr
をマウントし、handleDateChange
と呼ばれる別のハンドラを渡します。これはほとんど同じことを行い、start_date
とend_date
の値が変更されたときの状態に設定します。さて、このイベントを保存するためのAPIリクエストを実際に行う時が来ました。これを行うために、Appコンポーネントから関数を渡し、呼び出されたときにイベントを保存します。Appコンポーネントをこのように修正してみましょう。
コンポーネントをこのように更新してみましょう。
まず、
ApiService
をインポートし、Appコンポーネントのコンストラクタで新しいインスタンスを作成します。次に、apiServiceからの関数であるstoreEvent
というAddEvent
コンポーネントにプロップを渡します。次に、
AddEvent
コンポーネントのCreate Event
ボタンが作成された際に、このプロップを呼び出す必要があります。
Create Event
ボタンがクリックされると、this.props.storeEvent()
を呼び出し、状態をパラメータとして渡します。この関数は axios を呼び出し、イベントを保存するための HTTP リクエストを行います。開発者ツールで発信HTTPリクエストを確認すると、AdonisサーバーからのHTTPレスポンスが表示されているはずです。すべてのイベントのリストが表示されるまでは、作成されたことを確信することはできませんよね?次のステップでは、Adonis APIからすべてのイベントのリストをフェッチして表示します。
すべてのイベントをフェッチして表示する
すべてのイベントを取得するために、コンポーネントがマウントされた直後に
[GET]
リクエストを行い、結果を取得したら、その結果をステートに設定してコンポーネントに表示します。これを実現するために、componentDidMount
というReactのライフサイクルフックを追加してみましょう。この関数は、コンポーネントがマウントされるとすぐに実行されます。まず、イベントという新しいステートプロパティを空の配列に設定します。次に、
componentDidMount
関数の中で、APIリクエストをしてすべてのイベントを取得し、レスポンスが返ってきたら、その結果をstateに設定します。この時点でReact Dev toolsなどのツールを使ってコンポーネントの状態を検査すると、すべてのイベントのリストが表示されているはずです。次のステップは、このイベントのリストをコンポーネントに表示することです。このために作成した
Event
コンポーネントを使用します。App
コンポーネントをこのように変更してみましょう。各イベントをマッピングして、1つのイベントを所定の場所に表示します。現時点では、アプリケーションがマウントされると、対応するイベントのリストが表示されるはずです。
イベント コンポーネントはまだ動的ではありません。これは、特定のイベント(Appコンポーネントから渡された)のためのプロップを受け取り、代わりにそれらを表示する必要があります。この動作をサポートするように変更してみましょう。
これで、各イベントは
event
プロップを介して渡されたカスタムデータを表示するようになりました。現時点では、イベントを作成しても何も起こりません。より良いエクスペリエンスを得るために、App コンポーネントを修正して、
AddEvent
フォームを非表示にし、すべてのイベントを再度取得して、ユーザーが新しく作成されたイベントを見ることができるようにします。最初に、
fetchEvents
という新しい関数を作成します。次に、storeEventという新しい関数を作成します。この関数はAPIを呼び出して新しいイベントを保存し、レスポンスを取得したらfetchEvents
を呼び出してすべてのイベントを取得し、toggleShowCreateEventForm
を呼び出してcreateイベントフォームを非表示にします。ステップ8 - Deleteイベントの実装
最後のタスクは、イベントを削除できるようにすることです。App コンポーネント上でイベントを削除する関数を作成し、この関数を
Event
コンポーネントのプロップとして渡し、ユーザーが削除ボタンをクリックするたびにこの関数が呼び出されます。Appコンポーネントは次のようになります。新しく追加された関数
deleteEvent
はAPIサービスを呼び出し、イベントが削除されると、再びfetchEvents
を呼び出して、すべてのイベントの新鮮なコピーを取得します。最後に、Event
コンポーネントで、id
パラメータを指定してこの関数を呼び出します。このようにEvent
コンポーネントを修正します。すべての変更を行った後のプロジェクトの動作は次のようになります。
このアプリケーションが完成したことで、実際のプロジェクトの参考として使用できる最新のフルスタックJavascriptアプリケーションの基礎を手に入れることができます。
結論
このチュートリアルでは、Adonis.jsとReact.jsを使ってフルスタックのJavascriptデモアプリケーションを作成しました。REST APIの構築にはAdonis.js、APIの消費にはReact、アプリケーションのスタイリングにはBootstrap 4を使用しました。Adonis REST APIのソースコードはこちらのGitHubリポジトリに、ReactフロントエンドアプリケーションのソースコードはこちらのGitHubリポジトリにあります。
Adonisフレームワークについてもっと詳しく知りたい場合は、公式ドキュメントがとても便利で、ビデオチュートリアルも提供されています。
アリババクラウドは日本に2つのデータセンターを有し、世界で60を超えるアベラビリティーゾーンを有するアジア太平洋地域No.1(2019ガートナー)のクラウドインフラ事業者です。
アリババクラウドの詳細は、こちらからご覧ください。
アリババクラウドジャパン公式ページ
- 投稿日:2020-06-25T11:09:50+09:00
[初心者向け]Reactができるようになりたい ~React Hooksについて~
はじめに
今回はReactのHooksについてまとめていきます。
頑張っていきましょう。
今回は以下の記事を参考にしました。
日本一わかりやすいReact入門#8...React Hooksでstateを扱おう
Hookとは
Hookとは、端的に言えばクラスコンポーネントの機能をFunctionalコンポーネントでも使えるようにするためのものです。
具体的には、今まではクラスコンポーネントでしか持つことができなかったstateやライフサイクルをFunctionalコンポーネントで利用できるようになります。
今までReactの様々な機能にアクセスできるクラスコンポーネントと違い、一切のアクセスが許可されていなかったFunctionalコンポーネントをReactの機能へ接続(Hooks into)するという意味で、Hooksと呼ぶらしいです。
なぜHookを使うのか
察しの良い皆さんならこう思ったはずです。
「stateやライフサイクルメソッドが使いたいならクラスメソッド使えば良くね?」
確かに一理あります。
しかし、クラスコンポーネントには以下で示すような問題がありました。
- 処理が散らばりやすい
- thisを使いたくない
- 複数のライフサイクルメソッドに処理がまたがるのが嫌だ
- そもそもクラスコンポーネントの構文が複雑
- stateの扱い方が複雑
この中のいくつかの問題点を、さらに深く解説していきます。
処理が散らばりやすい
Reactを書いたことがある皆さんなら共感頂けると思いますが、クラスコンポーネントはメソッドをいくつも実装できるが故に処理が散り散りになりやすいんですよね。
子供のコンポーネントで行われる処理を、親のクラスコンポーネントのライフサイクルに定義して使いたくなりますよね。
具体例で話すなら、例えば
人間コンポーネント
を定義して、それに子供としてハサミコンポーネント
を渡したとします。このハサミコンポーネントの前に
紙が存在するとき
に、ハサミコンポーネントの切断
という機能を実装したいとします。人間コンポーネントをクラスコンポーネント、ハサミコンポーネントをFunctionalコンポーネントだとすると、
紙
はstateを持つ人間コンポーネントで管理することになりますし、紙の状態に応じた処理(ここでは切断する)もライフサイクルを持つ人間コンポーネントの中で書くことになりそうです。子供のコンポーネントがハサミコンポーネントのみならまだしも、他の様々なコンポーネントのstateやライフサイクルも人間コンポーネントで管理することになると、非常に煩雑になりそうですよね。
そもそも、
切断する
という処理はハサミコンポーネントの中の処理であるので、当然の思考としてハサミコンポーネントの中で管理するのが良さそうです。また、
紙
というstateも、紙の状態に応じたライフサイクルを用いた処理も、人間コンポーネントではなくハサミコンポーネントで管理するべきですよね。ここでハサミコンポーネントをクラスコンポーネントにしてしまっても良いのですが、それだと根源的な解決になりません。
そもそも、
ひとつの機能はひとつの場所に
という原則を守って書くことを強制してしまった方が良さそうです。そこで導入されたのがHookであり、Functionalコンポーネント自体にstateやライフサイクルを管理させるとうものです。
thisを使いたくない
Javascriptにおけるthisは、他の言語におけるthisとは違う挙動をします。
詳しくは以下の記事を御覧ください。
JavaScript の this を理解する多分一番分かりやすい説明
つまり、簡単に書くと
thisの使い方めっちゃむずい
ということです。こんなものはトラブルの元です。
できるだけ使わないようにしようという動きも多く、そのためクラスコンポーネントはできるだけ使いたくないと思う人も多いようです。
複数のライフサイクルメソッドに処理がまたがるのが嫌だ
クラスコンポーネントのライフサイクルメソッドは、時間の流れで処理を分割します。
そうすると、同じような機能が複数のライフサイクルメソッドに跨ってしまうことがありますよね。
そのように記述するよりも、
同じ機能は同じ場所
と言う方が分かりやすいと考える人も多いようです。ちなみに私もそう思います。React-Hooksの実装
それでは実際いHooksを実装してみましょう。
Hooksでstateの管理
まず、Hooksでstateの管理をしていきます。
HooksはFunctionalコンポーネントにおけるstateの管理やライフサイクルメソッドの実装に用いるんでしたね。
Hooksでstateを用いるときは、
useState
というメソッドを使います。実際にコードで確認してみましょう。
今回は、ScissorsコンポーネントというFunctionalコンポーネントを作成して、それを親コンポーネントであるAppコンポーネントから呼び出します。
そのScissorsコンポーネントに
cutting
とうstateを持たせて、ボタンを押すことで変化させるという機能を実装します。以下がコードです。
App.jsximport React from 'react'; import Scissors from './Scissors' const App = () => { return( <div> <Scissors /> </div> ) } export default AppこれはシンプルにScissorsコンポーネントを呼び出しているだけですね。以下がそのScissorsコンポーネントです。
Scissors.jsximport React, { useState } from 'react'; const Scissors = () => { const [cutting, changeCutting] = useState("NoCutting"); return( <div> <h1>{cutting}</h1> <button onClick={() => changeCutting("YesCutting!")}>change </button> </div> ) } export default ScissorsそれではHooksの部分を解説していきます。
以下の部分でuseStateをインポートしています。
import React, { useState } from 'react';これでインポートすることができました。
次の部分が、useStateを使う上で肝となる部分です。以下のコードです。
const [cutting, changeCutting] = useState("NoCutting");それでは解説します。
cutting
がstateであり、changeCutting
がstateを変更させる関数です。ちなみに、このchangeCutting
に引数を渡して実行すれば、cutting
の値がその引数に渡した値に変化します。つまり、このuseState関数は、
state
とstateを変更させる関数
を同時に定義していると考えることができますね。クラスコンポーネントでは、constructorの部分で
this.state = {}
という感じにstateを定義し、setState
を用いてそのstateを変更していたと思います。それでは、
useState
の引数の部分は何を意味するのでしょうか。正解は、
stateの初期値
になります。つまり、上のコードは
cutting
というstateを作成し、その初期値にNoCutting
を渡し、それと同時にそのstateを変更させる関数であるchangeCutting
を作成したことになります。またこのchangeCutting
は、実行したときにcutting
の値を引数に指定した値に変更させる関数になります。以下のコードで、ボタンをクリックしたときにこの
changeCutting
を実行しています。<button onClick={() => changeCutting("YesCutting!")}>change </button>buttonタグのonClickにアロー関数として
changeCutting
を実行したものを渡しています。onClickはボタンをクリックしたときに引数として渡された関数を実行するという機能なので、このように関数そのものを渡します。
実際にこのReactアプリの挙動を見てみましょう。
ここまでで、Hooksによるstate管理は終わりです。
Hooksによるライフサイクルの管理
Hooksによるライフサイクルメソッドの代替として、
useEffect
メソッドがあります。以下の三つのメソッドを代替することができます。
- coponentDidMount()
- componentDidUpdate()
- componentWillUnmount()
軽く解説します。
componentDidMountについて
componentDidMountはマウントが行われた直後に実行されるメソッドです。Ajaxを使ったデータフェッチ(初回)やイベントリスナのセットなどを行います。
componentDidUpdateについて
componentDidUpdateはstateの更新が行われた直後に行われるメソッドです。具体的には、stateが更新され、その後にrenderが走った後に呼び出されます。
stateがある閾値を超えたときに別の動作をするようにしたい
ときなどに使うと便利ですね。componentWillUnmountについて
componentWillUnmountは、コンポーネントが破棄される直前に呼び出されます。
具体的には、イベントリスナーを解除してメモリを開放するときなどに利用されます。
それでは、実際に
useEffect
メソッドを用いてこれらのライフサイクルメソッドを実装してみましょう。useEffectメソッドの実装
まず、最初にuseEffectメソッドの使い方解説を行います。
以下の記事を参考にしました。
第一引数のみ
第二引数を空っぽにすると、第一引数に指定したコールバック関数がrender毎に実行されます。
componentDidUpdate
と同じタイミングで呼ばれることになりますね。useEffect(() => { console.log("render") });しかし、これは公式のリファレンスで推奨されていない書き方なので、使わないようにしましょう。
第二引数を与える
空の配列が渡されたとき
useEffect(() => { console.log('mounting') }, [])第二引数に殻の配列が渡された場合、マウント時とアンマウント時のみ、第一引数に渡されたコールバック関数を実行します。
Reactはrenderが呼ばれるたびに
第二引数の値がrender前とrender後に変化したかどうか
を確認します。その時、変化していた場合にのみ第一引数に設定したコールバック関数を実行します。
今回は、第二引数に空の配列を指定しているため、マウント時のみ第一引数のコールバック関数が走るようになります。
componentDidMount
と同じタイミングになります。第二引数の配列に値が渡された場合
第二引数に値の配列が渡された場合、
renderの前後で値が変化した場合
に第一引数のコールバック関数が呼ばれます。const [Boolean, changeBoolean] = useState(true) useEffect(() => { console.log('changed') }, [Boolean])この場合、第二引数に渡した
Boolean
の値が変更されるたびに第一引数に渡したコールバック関数が呼ばれるようになります。マウント時とアンマウント時のみ実行
useEffectメソッドにおいては、第一引数のコールバック関数内においてreturnを行うと、そのreturnの中の処理がアンマウント時に実行されるようになります。
以下のコードです。
useEffect(() => { console.log("render") return () => { console.log("Unmounting!") } }, []}第二引数に空の配列を渡しているので、render毎に実行されることはありません。
つまり、
console.log("render")
の部分がマウント時のみ実行されるようになります。また、return後の関数が、アンマウント時に実行されるようになります。
終わりに
今回の記事はここまでになります。
お疲れさまでした。
- 投稿日:2020-06-25T08:52:16+09:00
PropsとStateの違い
Reactを学習していて、PropsとStateの違いってなんやろ
とふとした時に思い調べました。学習メモなのでふわっとしていますが、どうぞよしなに。
*間違いがあれば教えていただけると、ありがたいです。
【Propsとは】
・オブジェクト
・親コンポーネントからもらう値
・Propsを受け取る側の子コンポーネントではPropsを変化させれない
・親コンポーネントから変化させられる【Stateとは】
・オブジェクト
・コンポーネント自身で定義する
・初期値を設定したらsetStateでStateの値を変更する<まとめ>
Props→上から下に流れるデータ
State→コンポーネント自身が持つデータ
- 投稿日:2020-06-25T01:49:00+09:00
ReactでSemantic Uiを 使ってみる
■semantic ui react
yarn add semantic-ui-react※フォントを変えたいのでsemantic-cssは読み込まない
LESSを読むためにcracoをインストール
yarn add @craco/craco @semantic-ui-react/craco-less semantic-ui-less --devPackage JSONを書き換え
{ "scripts": { "start": "craco start", "build": "craco build", "test": "craco test", "eject": "craco eject" } }craco.config.jsを作成
module.exports = { plugins: [{ plugin: require('@semantic-ui-react/craco-less') }], }必要なbuildツールをインストール
npx @semantic-ui-react/bootstrapインストールされた新しいフォルダ内にあるtheme.configの設定を変更
src/semantic-ui/theme.config
/******************************* Folders *******************************/ @themesFolder : 'themes'; @siteFolder : '../../src/semantic-ui/site'; /******************************* Import Theme *******************************/ @import (multiple) "~semantic-ui-less/theme.less"; @fontPath : '../../../themes/@{theme}/assets/fonts';Index.jsでimport
import 'semantic-ui-less/semantic.less'font の変更
src/semantic-ui/site/globals/site.variables @headerFont : 'Muli', 'Noto Sans JP', sans-serif; @pageFont : 'Muli', 'Noto Sans JP', sans-serif; @googleFontFamily : 'Noto+Sans+JP:wght@300;400;700|Muli:wght@300;400;700';
- 投稿日:2020-06-25T01:38:34+09:00
node.jsでvercelを使って環境変数を設定するメモ
環境変数設定メモ
vercel では、環境変数を本番環境、プレビュー環境、および開発環境用に簡単に分けることができる。
手順
1. vercle プロジェクト設定の[ 全般]ページ に移動して、[環境変数] セクションを見つける。
2.環境変数の名前を入力する。
たとえば、
Node.js
を使用していて、SENTRY_KEY
という名前の環境変数を作成すると、コード内でprocess.env.SENTRY_KEY
で使用できるようになる。
環境 説明 Production 環境変数が次の本番デプロイメントに適用される。本番デプロイメントを作成するには、デフォルトのブランチにcommitをpushする。 Preview 環境変数は、プレビューデプロイメントに適用される。プレビューデプロイメントは、ブランチ(例えば my-new-feature
)にpushすると作成される。Development 環境変数は、プロジェクトをローカルで、 vercel dev
または任意の開発コマンドで実行するときに使用する。開発環境変数をダウンロードするには、vercel env pull
を実行する。
これだけ!
Enjoy Hacking!
参考
https://vercel.com/docs/v2/build-step?query=envirome#development-environment-variables