- 投稿日:2020-03-30T23:45:25+09:00
これからはじめる、Gatsbyのインストールから静的サイトのビルドまで
Gatsbyは次のWordpressとも言われている、Reactベースのオープンソースフレームワーク。
超高速なWebサイトやブログ、アプリを簡単に作ることができ、今最も注目されているCMSツールでもあります。
ここではGatsbyをこれからはじめる人のために、インストール〜静的サイトのビルドまでをサクッと解説していきます。
Node環境のインストール
まずは環境のチェック。nodeは11.10以降にする必要がある。
brew使ってたので、brewでnodeをアップデートする。
node入ってない人はここからダウンロードできる。
brew upgrade node // nodeをインストールしてない場合 brew install nodeインストールできたらnodeのバージョンチェック。
node -v v13.11.0Gatsbyのインストール
npm install -g gatsby-cli gatsby new gatsby-site cd gatsby-site gatsby develop
http://localhost:8000
にアクセス。ページが表示されればOK。静的サイトのビルド(生成)
コマンドで自動的にファイルを作成してくれる。
gatsby buildビルドすると、puglicフォルダに静的サイトが作成される。あとはサーバーにアップすればWebサイトを表示できる。
Gatsbyのスターターライブラリを使ったインストール
Gatsbyはデフォルトだけでなく、ブログやWebサイト、ポートフォリオサイトなどのスターターライブラリがあり、効率よく開発をスタートできる。
スターターライブラリ
https://www.gatsbyjs.org/starters/?v=2ブログを作りたい場合はこちら。
gatsby new gatsby-starter-blog https://github.com/gatsbyjs/gatsby-starter-blogGatsbyのリソース
ドキュメントがしっかりしてるので、そこ見ればだいたいのことはわかる。
プラグインやライブラリなどもリンクされてるので、公式のリソース集はチェックしておきましょう。
最新情報はTwitterやRedditを活用。
- 投稿日:2020-03-30T23:26:44+09:00
【24日目】React(コンポーネント,モーダル)
挨拶
こんばんは。
progateのReactはレッスンが少ないですね。
Udemyでも学習していこうと思います。本日の学び
progate React 3
コンポーネント
Lessonコンポーネントに渡されたpropsは「this.props.props名」で取得できる。
import React from 'react'; import Lesson from './Lesson'; class Main extends React.Component { render() { const lessonItem = { name: 'HTML & CSS', image: 'https://s3-ap-northeast-1.amazonaws.com/progate/shared/images/lesson/react/html.svg' } return ( <div className='main-wrapper'> <div className='main'> <div className='lesson-container'> <Lesson name={lessonItem.name} {/*props名=props値*/} image={lessonItem.image} /> </div> </div> </div> ); } } export default Main;モーダル
import React from 'react'; class Lesson extends React.Component { {/*Lseeonクラスの定義*/} constructor(props) { super(props); this.state = {isModalOpen: false}; {/*モーダルが表示されているか 初期値はfalse*/} } handleClickLesson() { this.setState({isModalOpen: true}); {/*モーダル開けるとき*/} } handleClickClose(){ this.setState({isModalOpen:false}); {/*モーダル閉じるとき*/} } render() { let modal; {/*今は空*/} if (this.state.isModalOpen) { {/*trueで下記が変数に入る*/} modal = ( <div className='modal'> <div className='modal-inner'> <div className='modal-header'></div> <div className='modal-introduction'> <h2>{this.props.name}</h2> <p>{this.props.introduction}</p> </div> <button className='modal-close-btn' onClick={()=>{this.handleClickClose()}} > とじる </button> </div> </div> ); } return ( <div className='lesson-card'> <div className='lesson-item' onClick={() => {this.handleClickLesson()}} {/*クリックでhandleClickLessonを呼び出す*/} > <p>{this.props.name}</p> <img src={this.props.image} /> </div> {modal} {/*trueで有効*/} </div> ); } } export default Lesson;
- 投稿日:2020-03-30T13:48:59+09:00
環境変数管理の便利ツール
環境変数管理
背景
秘密鍵を使うこともあり,
sample用の.env.sample
と開発用の.env
ファイルを分けている
.env.sample
をコミットに残すため、こちらを正として.env
を管理したいインストール方法
go get github.com/locona/envdef/cmd/envdef使い方
テストデータ準備
プロジェクトのルートにある.envファイルにアプリケーション構成を追加します。
S3_BUCKET=YOURS3BUCKET SECRET_KEY=YOURSECRETKEYGOESHEREプロジェクトのルートにある
.env.sample
ファイルS3_BUCKET=YOURS3BUCKET SECRET_KEY=YOURSECRETKEYGOESHERE REGION=REGION実行
次に実行します
envdefその結果、
.env.new
ファイルが作成されますREGION=REGION S3_BUCKET=YOURS3BUCKET SECRET_KEY=YOURSECRETKEYGOESHEREconsole にも変更点が表示されます
まとめ
envdef を使うことにより、不要になった環境変数や追加された環境変数の管理が楽になりました
- 投稿日:2020-03-30T11:37:55+09:00
React Reduxには今後Redux Toolkitも使うのがいいと思う
ReactをTypeScriptで始めることが随分楽になったと感じています。Create React Appの以下のコマンドでOKです。
$ npx create-react-app my-app --template typescripthttps://create-react-app.dev/docs/adding-typescript/#installation
2020年2月の中頃からReduxのテンプレートが利用可能となり、以下のコマンドで始めることができます。
$ npx create-react-app my-app --template redux # or $ npx create-react-app my-app --template redux-typescripthttps://github.com/reduxjs/cra-template-redux
このReduxテンプレートにはRedux Toolkitが使われています。https://redux-toolkit.js.org/
本格的に利用していくのはこれからですが、使わない場合と比べてここが便利だ(そうだ)というあたりを紹介します。利点
初期設定が簡単
次のmiddlewareが設定済みとなります。
- Redux Thunk
- immutable-state-invariant
- serializable-state-invariant-middleware
Redux Thunkは非同期通信のためのライブラリで、他2つは開発用のmiddlewareでReduxで禁止しているstateの変更を検知してくれます。
また、Redux Devtools Extensionも有効になっています。
これらを自分で適用しようとすると少々面倒です。createSliceでActionのコードは不要に
公式ドキュメントからの抜粋となります
const counterSlice = createSlice({ name: 'counter', initialState: 0, reducers: { increment: state => state + 1, decrement: state => state - 1 } }) const store = configureStore({ reducer: counterSlice.reducer }) const { actions, reducer } = counterSlice const { increment, decrement } = actionsこんな感じでAction, Reducerを定義できます。これによりほぼActionのコードがなくなるのではと期待しています。今まではComponent, Action, Reducerに対してロジックが多少入ることが気になっていましたが、Component, Reducerでそれぞれの責務でロジックを実装できそうです
Reducerのネストはいつも通りな感じです。
const sliceA = createSlice({ name: "reducerA", //... }) const sliceB = createSlice({ name: "reducerB", //... }) import { combineReducers } from "@reduxjs/toolkit" const mergeReducer = combineReducers({ reducerA: sliceA.reducer, reducerB: sliceB.reducer, })非同期通信にはRedux Thunkが採用
const createUser = createAsyncThunk( 'users/createUser', async () => { // API処理 } )createAsyncThunkでは次の3つのActionを生成してくれます。
- pending
- fulfilled
- rejected
sliceではextraReducersのbuilderを利用して追加します。createAsyncThunkで定義されたActionを利用するためです。
reducer.jsconst userSlice = createSlice({ name: "user", initialState: { user: null, }, reducers: {}, extraReducers: builder => { builder.addCase(createUser.pending, (state, action) => {}) builder.addCase(createUser.fulfilled, (state, action) => {}) builder.addCase(createUser.rejected, (state, action) => {}) } })component.jsximport { useDispatch } from "react-redux" function UserComponent() { const dispatch = useDispatch() const handleSubmit = async () => { const resultAction = await dispatch(createUser()) // createAsyncThunkで生成されるActionと比較して処理を変更できる if (createUser.fulfilled.match(resultAction)) { // success } else { // error } }; return ( <div> <form></form> <button onClick={handleSubmit}>submit</button> </div> ) }やっておいた方がいいこと
RootReducerの型定義
TypeScriptで利用する際に用意しておいた方がいいです。以下で定義しておきます。
store.tsimport { combineReducers, configureStore } from "@reduxjs/toolkit" export const rootReducer = combineReducers({ moduleA: moduleAReducer, }) export type RootReducerType = ReturnType<typeof RootReducer>RootとなるReducerの型定義はあると便利ぐらいの気持ちです。
useDispatchのラップ
store.tsimport { configureStore } from "@reduxjs/toolkit" const store = configureStore({ reducer: rootReducer }) export type AppDispatch = typeof store.dispatchcustomHooks.tsimport { useDispatch } from "react-redux" function useAppDispatch(): AppDispatch { return useDispatch<AppDispatch>() }createAsyncThunkで型定義のエラーを起こさないためです。
注意点
ImmerによるReducerのstateのImmutable
以下のようにstateを直接変更するようなコードを書いても問題ありません。Redux ToolkitではImmerを利用しており、実際にstateを変更しているわけではないとのことです。
interface CounterState { value: number; } const initialState: CounterState = { value: 0, }; export const slice = createSlice({ name: 'counter', initialState, reducers: { increment: state => { state.value += 1; } }, });まとめ
煩雑な設定がなくなり、ActionやReducerの実装も統一できそうです。これからReduxを始める人、そうでない人にもおすすめです
参考
- 投稿日:2020-03-30T00:21:24+09:00
[React] 可読性の高いテストを爆速で書くための個人的テンプレート
React コンポーネントのテストを爆速で書くために個人的に従っているパターンを紹介します。サンプルでは Jest と Enzyme を使っていますが、論旨はこれらのツールに依存しないものになっているはずです。
この記事では、題材として画像のような2ステップのログイン画面をテストすることを考えます1。
このコンポーネントはユーザ名、パスワード、今いるステップ (1ステップ目か2ステップ目か) を状態として持っているものとします。2ステップ目でユーザがログインボタンを押すと、ユーザ名とパスワードを引数にしてコールバックを呼び出します。コンポーネントのシグニチャは下記のようなものだとしましょう。
LoginForm.jsexport default function LoginForm({ onLoginButtonClick }) {/*...*/}ファクトリ関数にすべてを押し込める
テストを書き始めるにあたり、コンポーネントのマウント、モック関数の作成など、諸々のセットアップを担当するファクトリ関数を作成します。ユーザインタラクションをシミュレートするためのあらゆる面倒をこの関数に押し付けます。
LoginForm.test.jsimport React from "react"; import { mount } from "enzyme"; import LoginForm from "./LoginForm"; function createTestEnv() { // モックの作成 const onLoginButtonClick = jest.fn(); // コンポーネントのマウント const wrapper = mount(<LoginForm onLoginButtonClick={onLoginButtonClick} />); // ユーザインタラクションをシミュレートする便利関数 function prompt() { return wrapper.text(); } function enterUsername(username) { wrapper .find('input[name="username"]') .simulate("change", { target: { value: username } }); } function enterPassword(password) { wrapper .find('input[name="password"]') .simulate("change", { target: { value: password } }); } function clickNext() { wrapper.find('[children*="NEXT"]').simulate("click"); } function clickLogin() { wrapper.find('[children*="LOGIN"]').simulate("click"); } return { onLoginButtonClick, wrapper, prompt, enterUsername, enterPassword, clickNext, clickLogin }; }テスト本体からはファクトリ関数を呼び出すだけ
上で定義したファクトリ関数を各テストの冒頭で呼び出します。簡単!
LoginForm.test.jsの続きdescribe("LoginForm", () => { describe("the first step", () => { it("prompts for a username", () => { const { prompt } = createTestEnv(); expect(prompt()).toContain("Enter your username"); }); }); describe("the second step", () => { it("prompts for a password", () => { const { enterUsername, clickNext, prompt } = createTestEnv(); enterUsername("alice"); clickNext(); expect(prompt()).toContain("Enter your password"); }); }); describe("the onLoginButtonClick callback", () => { it("gets called with username and password", () => { const { enterUsername, enterPassword, clickNext, clickLogin, onLoginButtonClick } = createTestEnv(); enterUsername("alice"); clickNext(); enterPassword("pAsSwOrD"); clickLogin(); expect(onLoginButtonClick).toBeCalledWith({ username: "alice", password: "pAsSwOrD" }); }); }); });何がうれしいのか
テスト本体の可読性が高まる
この書き方で気に入っているのは、面倒ごとをファクトリ関数に押し込むことでテスト本体の可読性が高まることです。例の中で最も長いテストでさえ自然言語として読むことができるくらいです。
enterUsername("alice"); clickNext(); enterPassword("pAsSwOrD"); clickLogin(); expect(onLoginButtonClick).toBeCalledWith({ username: "alice", password: "pAsSwOrD" });実装依存が一か所にまとまる
ファクトリ関数に面倒を押し付けることの二つ目のメリットは、実装依存のコードが一か所に集まることです。UIのテストたるもの、常に「ユーザーから見えるものをテストする」のが理想ですが、現実にはそれが難しい場面も存在します。たとえば「フロッピーディスクのアイコンをクリックする」という操作をテストコードに落とし込むと、
wrapper.find('img[src="./icons/floppy-disk-icon.png"]').click();のようにせざるを得ません。しかしここに登場する「フロッピーディスクアイコンのファイル名」は明らかに実装の詳細です。こうしたコードがテスト本体に何度も現れると、アイコンのファイル形式を png から svg に差し替えるといった軽微な変更を行うだけで、テストを何か所も変更する羽目になります。辛いですね。
一方で、実装依存のコードをファクトリ関数の中に押し込めておけば、ファクトリ関数の中の一か所を書き換えるだけでよくなります。実装依存のコードを一か所にかき集めることで、実装の変更の影響範囲を最小化できるのです。もちろん理想は実装依存が少ないテストコードです。
おわりに
私はここ最近、専ら本記事で紹介したスタイルで React コンポーネントのテストを書いています。悩む時間を減らして生産効率を上げるために、このような決まりきったパターンに従うことは有効だと感じています。スニペットを活用すればコーディングをさらに高速化できます。
このスタイルに起因する大きな問題は今のところ発生していません。しかし類例をあまり見かけないので、こうしたスタイルには問題があるものの、私がそれに気づいていないだけかもしれません。もしそのように思われる場合は、ぜひコメント欄でお知らせください。