- 投稿日:2021-03-02T22:32:30+09:00
pm2でnext js を永続化させる方法について。プロダクション環境での注意点も含めてご紹介
next jsを永続化し落ちないようにするために試行錯誤したのでご紹介。
next jsをAWS ec2 のような環境に直接デプロイ(npm run start)すると安定せず突然サイトが落ちることがあります。
pm2を使用すると自動的にサーバーを再起動&監視してくれプロダクション環境でも安定して使用可能です。Step1
pm2 を環境にインストール
npm install -g pm2上記のコマンドをPC(もしくはクラウド環境)に打ち込むとインストールできます。
Step2
next jsをビルドする。
npm run buildビルドすることにより、高速にページが開けるようになります。
Step3
pm2でnext jsを永続化
pm2 start npm --name "next" -- startちなみに以下のパスから起動すると、ビルド前の非効率なサーバーが永続化されるので要注意。
ページスピードインサイトで構築中のサイトを”startで起動したもの”と"以下のパスで起動したも"の比較すると、ページの送信サイズが10倍ほど違うという結果になりました。(当然重すぎてまともな時間で動きませんでした。)
./node_modules/next/dist/bin/nextStep4
pm2でサーバーが永続化されていることを確認
pm2 list以上で完了!
- 投稿日:2021-03-02T22:32:30+09:00
pm2でnext js を永続化させる方法について。表示速度向上で試行錯誤したのでメモ
next jsを永続化し落ちないようにするために試行錯誤したのでご紹介。
next jsをAWS ec2 のような環境に直接デプロイ(npm run start)すると安定せず突然サイトが落ちることがあります。
pm2を使用すると自動的にサーバーを再起動&監視してくれプロダクション環境でも安定して使用可能です。Step1
pm2 を環境にインストール
npm install -g pm2上記のコマンドをPC(もしくはクラウド環境)に打ち込むとインストールできます。
Step2
next jsをビルドする。
npm run buildビルドすることにより、高速にページが開けるようになります。
Step3
pm2でnext jsを永続化
pm2 start npm --name "next" -- startちなみに以下のパスから起動すると、ビルド前の非効率なサーバーが永続化されるので要注意。(googleで検索したらよく出てくるやつ)
ページスピードインサイトで構築中のサイトを”startで起動したもの”と"以下のパスで起動したも"の比較すると、ページの送信サイズが10倍ほど違うという結果になりました。(当然重すぎてまともな時間で動きませんでした。)
startだとかなり早くなります。
./node_modules/next/dist/bin/nextStep4
pm2でサーバーが永続化されていることを確認
pm2 list以上で完了!
- 投稿日:2021-03-02T22:14:07+09:00
TypeScriptをなんとなく理解する③ ~型を組み合わせる: Generics~
この記事は何?
TypeScriptとは何か、何がいいのかを伝えようと頑張った記事の第3弾です!
今回は、型の使いまわしであるGenericsについて見ていきます。
過去の記事、続編も合わせて御覧ください!
・ JavaScriptを知っている方がTypeScriptをなんとなく理解するための記事① ~はじめに~
・ TypeScriptをなんとなく理解する② ~型を組み合わせる: Union~
・ TypeScriptをなんとなく理解する③ ~型を組み合わせる: Generics~← この記事
・ TypeScriptをなんとなく理解する④ ~構造型~ (3/3更新予定)型の組み合わせとは?
TypeScriptでは、型と型を組み合わせて新しく型を作り上げることが出来ます。
この型の組み合わせの方法は2つあります。
1つは、Union、もう1つは、Genericsです。この記事では、Genericsの概要について説明していきます。
※ Unionについては、前回の記事で紹介しています。
Genericsとは?
TypeScriptにおけるGenerics(ジェネリクス)を学ぶ前に、そもそもGenericsの英単語の意味を確認してみます。
genericsとは
一般的な、ジェネリックの、属の、ノーブランド商品なんだか、定まっていないというか、汎用的な意味合いを感じます。
実際に、TypeScriptにおける、Genericsも同じような意味です。
TypeScriptにおけるGenericsは、利用されるまで型が確定しない、クラス, 関数, インターフェイスなどなど...を実現するためのものです。事前にガッチガチに型定義するのもいいですが、汎用的に使える型もほしいです。
そこで、Genericsが活躍します。もう少しイメージを掴むために、実際にコードを見ていきます。
まず、今までの知識を使って、関数を作ってみます。
const returnStrArray = (value1: string, value2: string):string[] => { return [value1, value2]; }; const returnNumberArray = (value1: number, value2: number):number[] => { return [value1, value2]; }; const penguinsName = returnStrArray('コウテイペンギン','アデリーペンギン'); // ['コウテイペンギン', 'アデリーペンギン'] const penguinsWeight = returnNumberArray(1000, 50); // [1000, 50]上のコードは、引数
value1
,value2
を含む配列を返す関数です。
...同じようなことを2回もやるのって冗長じゃないですか...?そこで、汎用的なことを出来るGenericsを利用します?
const returnArray = <T>(value1: T, value2: T):T[] => { return [value1, value2]; } const penguinsNames = returnArray<string>('コウテイペンギン','アデリーペンギン'); // ['コウテイペンギン', 'アデリーペンギン'] const penguinsWeights = returnArray<number>(1000, 50); // [1000, 50]
T
は何にでも変わる型です。const penguinsNames = returnArray<string>('コウテイペンギン','アデリーペンギン');
<string>
のように指定すると、T
がstring
であることを示します。なので、以下の型を定義した関数と同義になります。const returnArray = (value1: string, value2: string):string[] => { return [value1, value2]; }アロー関数でGenericsを利用するときは、
<T>
を()
の前につけてあげる必要があるため<T>()
のような形になっています。このように、Genericsを利用することで汎用的で使いまわし可能な型定義をすることが出来ます。
TypeScriptにおけるGenericsは、利用されるまで型が確定しない、クラス, 関数, インターフェイスなどなど...を実現するためのものです。
この伏線を回収することが出来たと思います。
T
は<string>
のように指定するまで型が確定しないことから、今回の例では、利用するまで型が確定しない関数を実現出来たと思います。
const penguinsNames = returnArray<string>('コウテイペンギン','アデリーペンギン'); // 利用したから型が確定他にも、
interface funcs<T> { add: (obj: T) => void; get: () => T; }みたいに、独自の型を宣言出来たりもします。
おわりに
できるだけわかりやすく伝えようとしましたが、理解出来そうでしょうか?
この記事だけで理解していただけましたら、是非LGTM✨いただければと思います。理解できない方がいた場合は...もっとわかりやすく伝えられるよう精進します...!
参考文献
- 投稿日:2021-03-02T22:14:07+09:00
TypeScriptをなんとなく理解するための記事③ ~型を組み合わせる: Generics~
この記事は何?
TypeScriptとは何か、何がいいのかを伝えようと頑張った記事の第3弾です!
今回は、型の使いまわしであるGenericsについて見ていきます。
過去の記事、続編も合わせて御覧ください!
・ JavaScriptを知っている方がTypeScriptをなんとなく理解するための記事① ~はじめに~
・ TypeScriptをなんとなく理解するための記事② ~型を組み合わせる: Union~
・ TypeScriptをなんとなく理解するための記事③ ~型を組み合わせる: Generics~← この記事
・ TypeScriptをなんとなく理解するための記事④ ~構造型~ (3/3更新予定)型の組み合わせとは?
TypeScriptでは、型と型を組み合わせて新しく型を作り上げることが出来ます。
この型の組み合わせの方法は2つあります。
1つは、Union、もう1つは、Genericsです。この記事では、Genericsの概要について説明していきます。
※ Unionについては、前回の記事で紹介しています。
Genericsとは?
TypeScriptにおけるGenerics(ジェネリクス)を学ぶ前に、そもそもGenericsの英単語の意味を確認してみます。
genericsとは
一般的な、ジェネリックの、属の、ノーブランド商品なんだか、定まっていないというか、汎用的な意味合いを感じます。
実際に、TypeScriptにおける、Genericsも同じような意味です。
TypeScriptにおけるGenericsは、利用されるまで型が確定しない、クラス, 関数, インターフェイスなどなど...を実現するためのものです。事前にガッチガチに型定義するのもいいですが、汎用的に使える型もほしいです。
そこで、Genericsが活躍します。もう少しイメージを掴むために、実際にコードを見ていきます。
まず、今までの知識を使って、関数を作ってみます。
// 引数value1, value2は文字列型で、返り値は各要素が文字列の配列 const returnStrArray = (value1: string, value2: string):string[] => { return [value1, value2]; }; // 引数value1, value2は数値型で、返り値は各要素が数値の配列 const returnNumberArray = (value1: number, value2: number):number[] => { return [value1, value2]; }; const penguinsName = returnStrArray('コウテイペンギン','アデリーペンギン'); // ['コウテイペンギン', 'アデリーペンギン'] const penguinsWeight = returnNumberArray(1000, 50); // [1000, 50]上のコードは、引数
value1
,value2
を含む配列を返す関数です。
...同じようなことを2回もやるのって冗長じゃないですか...?そこで、汎用的なことを出来るGenericsを利用します?
const returnArray = <T>(value1: T, value2: T):T[] => { return [value1, value2]; } const penguinsNames = returnArray<string>('コウテイペンギン','アデリーペンギン'); // ['コウテイペンギン', 'アデリーペンギン'] const penguinsWeights = returnArray<number>(1000, 50); // [1000, 50]
T
は何にでも変わる型です。// T → string const penguinsNames = returnArray<string>('コウテイペンギン','アデリーペンギン');
<string>
のように指定すると、T
がstring
であることを示します。なので、以下の型を定義した関数と同義になります。const returnArray = (value1: string, value2: string):string[] => { return [value1, value2]; }アロー関数でGenericsを利用するときは、
<T>
を()
の前につけてあげる必要があるため<T>()
のような形になっています。このように、Genericsを利用することで汎用的で使いまわし可能な型定義をすることが出来ます。
TypeScriptにおけるGenericsは、利用されるまで型が確定しない、クラス, 関数, インターフェイスなどなど...を実現するためのものです。
この伏線を回収することが出来たと思います。
T
は<string>
のように指定するまで型が確定しないことから、今回の例では、利用するまで型が確定しない関数を実現出来たと思います。
const penguinsNames = returnArray<string>('コウテイペンギン','アデリーペンギン'); // 利用したから型が確定他にも、
interface funcs<T> { add: (obj: T) => void; get: () => T; }みたいに、独自の型を宣言出来たりもします。
おわりに
できるだけわかりやすく伝えようとしましたが、理解出来そうでしょうか?
この記事だけで理解していただけましたら、是非LGTM✨いただければと思います。理解できない方がいた場合は...もっとわかりやすく伝えられるよう精進します...!
参考文献
- 投稿日:2021-03-02T22:14:07+09:00
TypeScriptをなんとなく理解するための記事③ ~汎用的な型を作成する: Generics~
この記事は何?
TypeScriptとは何か、何がいいのかを伝えようと頑張った記事の第3弾です!
今回は、型の使いまわしであるGenericsについて見ていきます。
@ 過去の記事、続編?も合わせて御覧ください!
1. JavaScriptを知っている方がTypeScriptをなんとなく理解するための記事① ~はじめに~
2. TypeScriptをなんとなく理解するための記事② ~型を組み合わせる: Union~
3. TypeScriptをなんとなく理解するための記事③ ~汎用的な型を作成する: Generics~← この記事
4. TypeScriptをなんとなく理解するための記事④ ~構造型~
@ TypeScriptがなんとなく理解できたら、是非インストールして、触ってみてください!
? 【画像で説明】シンプルにTypeScriptを導入して使う方法型の組み合わせとは?
TypeScriptでは、型と型を組み合わせて新しく型を作り上げることが出来ます。
この型の組み合わせの方法は2つあります。
1つは、Union、もう1つは、Genericsです。この記事では、Genericsの概要について説明していきます。
※ Unionについては、前回の記事で紹介しています。
Genericsとは?
TypeScriptにおけるGenerics(ジェネリクス)を学ぶ前に、そもそもGenericsの英単語の意味を確認してみます。
genericsとは
一般的な、ジェネリックの、属の、ノーブランド商品なんだか、定まっていないというか、汎用的な意味合いを感じます。
実際に、TypeScriptにおける、Genericsも同じような意味です。
TypeScriptにおけるGenericsは、利用されるまで型が確定しない、クラス, 関数, インターフェイスなどなど...を実現するためのものです。事前にガッチガチに型定義するのもいいですが、汎用的に使える型もほしいです。
そこで、Genericsが活躍します。もう少しイメージを掴むために、実際にコードを見ていきます。
まず、今までの知識を使って、関数を作ってみます。
// 引数value1, value2は文字列型で、返り値は各要素が文字列の配列 const returnStrArray = (value1: string, value2: string):string[] => { return [value1, value2]; }; // 引数value1, value2は数値型で、返り値は各要素が数値の配列 const returnNumberArray = (value1: number, value2: number):number[] => { return [value1, value2]; }; const penguinsName = returnStrArray('コウテイペンギン','アデリーペンギン'); // ['コウテイペンギン', 'アデリーペンギン'] const penguinsWeight = returnNumberArray(1000, 50); // [1000, 50]上のコードは、引数
value1
,value2
を含む配列を返す関数です。
...同じようなことを2回もやるのって冗長じゃないですか...?そこで、汎用的なことを出来るGenericsを利用します?
const returnArray = <T>(value1: T, value2: T):T[] => { return [value1, value2]; } const penguinsNames = returnArray<string>('コウテイペンギン','アデリーペンギン'); // ['コウテイペンギン', 'アデリーペンギン'] const penguinsWeights = returnArray<number>(1000, 50); // [1000, 50]
T
は何にでも変わる型です。// T → string const penguinsNames = returnArray<string>('コウテイペンギン','アデリーペンギン');
<string>
のように指定すると、T
がstring
であることを示します。なので、以下の型を定義した関数と同義になります。const returnArray = (value1: string, value2: string):string[] => { return [value1, value2]; }アロー関数でGenericsを利用するときは、
<T>
を()
の前につけてあげる必要があるため<T>()
のような形になっています。このように、Genericsを利用することで汎用的で使いまわし可能な型定義をすることが出来ます。
TypeScriptにおけるGenericsは、利用されるまで型が確定しない、クラス, 関数, インターフェイスなどなど...を実現するためのものです。
この伏線を回収することが出来たと思います。
T
は<string>
のように指定するまで型が確定しないことから、今回の例では、利用するまで型が確定しない関数を実現出来たと思います。
const penguinsNames = returnArray<string>('コウテイペンギン','アデリーペンギン'); // 利用したから型が確定他にも、
interface funcs<T> { add: (obj: T) => void; get: () => T; }みたいに、独自の型を宣言出来たりもします。
おわりに
できるだけわかりやすく伝えようとしましたが、理解出来そうでしょうか?
この記事だけで理解していただけましたら、是非LGTM✨いただければと思います。理解できない方がいた場合は...もっとわかりやすく伝えられるよう精進します...!
Next: TypeScriptをなんとなく理解するための記事④ ~構造型~
@ ハンズオンも書いたので、さっそく使ってみたい人は是非!
?【TypeScriptハンズオン①】男もすなるTypeScriptといふものを、女もしてみむとてするなり参考文献
- 投稿日:2021-03-02T21:13:36+09:00
Reactのmaterial-tableで外部APIを利用している場合のソート実装でやったこと
目的
Reactのmaterial-tableで、dataに外部APIを利用している場合のソート実装とスタイル調整の覚書です
バージョン
下記バージョンで確認しました
- React 17.0
- material-table 1.69.2
- material-ui-core 4.11.3
- lodash 4.17.21
公式サンプル
データに外部APIを利用する方法は 公式のRemote Data Previewの通りですが、公式サンプルではソートが出来ません。
これは、変更があるたびに新しいquery objectで関数が呼ばれるのですが、呼び出しているAPI reqres.in でソートに対応していないからです。ソートの実装方法
ソートするとデータ変更が走り
query
にorderBy
とorderDirection
が連携されるので、これを利用してソートを実装します。
案1 APIでソートに対応する
リクエストパラメータで指定された項目、並び順でソートしてレスポンスを返すAPIを作成し、UIから呼び出す方法です
UIからAPIに連携するパラメータ
ページングするので、ソート情報と合わせてページング情報もAPIに連携します。
query.pageSize
とquery.page
はoptionsでページングを利用しない設定をしない場合でも存在するので必須とみなして良いでしょう。
初期表示時などquery.orderBy
とquery.sortDirection
が存在しない場合はAPIのリクエストパラメータに含める必要はありません。下記リクエストパラメータをAPIに連携すれば良いと思いますが、実際の要件によるので確認してください。
- ページング情報:必須
- 1ページあたりの件数 (
query.pageSize
)- 現在何ページか (
query.page
+ 1)- ソート情報:任意
- ソートする項目 (
query.orderBy.field
)- ソート順 (
query.orderDirection
)APIでの対応
UI側からのリクエストパラメータを受け付ける
セキュリティ対策で、リクエストを受け付けた後はバリデーションを行いましょう。
データ検索処理
連携されたリクエストパラメータを利用して、データの検索を行います。
動的SQLでページング、ソートを行うことになるでしょう。
ソートする項目はUI上のフィールド名のため、データベースのカラム名とUI上のフィールド名の変換を持つ必要があるかもしれません。APIレスポンスの作成と返却
公式のUsageに従い下記をレスポンスで返却します。JSONが便利です。
https://material-table.com/#/docs/features/remote-data
- 検索結果
- material-tableの
columns
で指定するフィールドが必要です- テーブルに表示する全レコード件数
- ページング、ソート有無関係ない、テーブルの全件数です
- ページングする場合、何件中何件の形で表示されるため必要です
- 現在のページ数
案2 API返却結果をUI側でソートする
API仕様上ソート結果を反映できない場合は、lodashなどを使って
result.data
をソートします。初期表示時など
query.orderBy
とquery.sortDirection
が存在しない場合は、ソートせずresult.data
をそのままdataに設定します。おまけ:スタイルの調整
hover,activeの色の変更
スタイル次第でこのように、項目をクリックしてソートした後に文字が見えない状態になることがあります。
- hoverしたときは背景とほぼ同じ色が利用される
- ソート後にマウスを項目から離した後も、
MuiTableSortLabel-active
の背景色が黒 のが理由なので、Material UIのテーマをオーバライドしてMuiTableSortLabel
のスタイルを付けます。const theme = createMuiTheme({ overrides: { MuiTableSortLabel: { root: { color: "#fff", "&:hover": { color: "#fff !important" } }, active: { color: "#fff !important" } } } });ここではとりあえず表示させたいので
!important
を付けて優先順位をあげましたが、StackOverflowの2件目の回答『Solution for your problem is following:』も良さそうです。
ソートアイコンのカスタマイズ
ソートアイコンのサイズが大きい、背景色やスタイルによってはソート操作後にアイコンが見にくい、といった時はカスタマイズできます。
DevelopersIOさんのこちらの記事の通りです。
動作サンプル
CodeSandboxのサンプルです。このページの説明の『案2 API返却結果をUI側でソートする』と『スタイルの調整』を実装しています。
修正していろいろな挙動を試してみてください。
https://codesandbox.io/s/material-table-remote-data-sort-demo-vgfhm?file=/src/App.js参考
- 投稿日:2021-03-02T19:45:58+09:00
TypeScriptをなんとなく理解する② ~型を組み合わせる: Union~
この記事は何?
TypeScriptとは何か、何がいいのかを伝えようと頑張った記事の第2弾です!
今回は、型を組み合わせて新たな型を生成する、
Unionについて見ていきます。過去の記事、続編も合わせて御覧ください!
・ JavaScriptを知っている方がTypeScriptをなんとなく理解するための記事① ~はじめに~
・ TypeScriptをなんとなく理解する② ~型を組み合わせる: Union~← この記事
・ TypeScriptをなんとなく理解する③ ~型を組み合わせる: Generics~
・ TypeScriptをなんとなく理解する④ ~構造型~ (3/3更新予定)型の組み合わせとは?
TypeScriptでは、型と型を組み合わせて新しく型を作り上げることが出来ます。
この型の組み合わせの方法は2つあります。
1つは、Union、もう1つは、Genericsです。この記事では、Unionの概要について説明していきます。
Unionによる型の作成
unionの基本
まずは、Unioinを使わずに型を作ってみます。
型はtype
を利用して、以下のように作成します。type Fish = "sanma";新しく
Fish
型を作成しました。
このFish
型は、文字列(string)のsanma
のみを許容する型です。
そのため、この型を使って以下のように、定数lunch
を定義できます。type Fish = "sanma"; const lunch: Fish = "sanma";
lunch
はFish
型なので、"sanma"
のみ許容します。
つまり、ランチにはサンマしか食べることが出来ません。
実際にlunch
にサンマ以外を定義しようとすると...const lunch: Fish = "iwana"; // タイプ '"iwana"'はタイプ '"sanma"'に割り当てることができません。ts(2322)
Fish
型のlunch
には、"iwana"
を定義することが出来ませんでした。
ランチには、サンマもイワナも食べるので、どちらも許容したいです。
そこで、Union
を利用します。Union
は|
を利用して次のように記述します。type Fish = "sanma" | "iwana"; const lunch: Fish = "iwana";このように
|
を利用してFish
型に"sanma"
,"iwana"
に絞る事ができます。ちなみに、
"sanma"
,"iwana"
以外は許容されません。type Fish = "sanma" | "iwana"; const lunch: Fish = "iwana"; const dinner: Fish = "sanma"; const breakfirst: Fish = "saba"; // タイプ '"saba"'はタイプ 'Fish'に割り当てることができません。もちろん数値も扱うことができます。
type AndroidVersion = 9 | 10 | 11; const myAndroidOsVersion: AndroidVersion = 11;ちょっと発展した型の作成
以上では、明確な文字や数値に限定して、型を作成しました。
ここまで厳格にしなくても、「文字列string
はOK!」「文字列の入った配列string[]
はOK!」ということも出来ます。具体的には、以下のような記述方法です。
type Food = string | string[]; const branch: Food = 'cake'; const nightMeal: Food = ['ramen', 'onigiri', 'potechi']; const theLastSupper: Food = ['ramen', 'onigiri', 1498]; // タイプ「number」はタイプ「string」に割り当てることができません。ts(2322)レオナルド・ダ・ヴィンチ作の最後の晩餐(
theLastSupper
)は、1498年に完成しましたが、これは数値であり、文字列でないのでエラーが起きます。ちなみに、このような
Union
で型を定義した際に便利なのが型のチェックです。以下のように、型のチェックをすることができます。
タイプ 述語 文字列 typeof s === "string"
数値 typeof n === "number"
ブール値 typeof b === "boolean"
未定義 typeof undefined === "undefined"
関数 typeof f === "function"
配列 Array.isArray(a)
これを使って、型によって条件分岐をすることが出来ます。
const healthCheck = (food: Food): string => { if (typeof food === "string") { return `it's OK`; } else { return `it's Bad`; } }; console.log(healthCheck(["ramen", "onigiri", "potechi"])); // it's Badおわりに
今回はUnionを使って、型を結合してみました!
型を組み合わせて、自分だけのユニークな型を作ってみましょう!※ 「そういえば、前回、Interfaceが出てきたけどtypeと何が違うの...?」と思った方もいるかもしれません。今後、この違いに関しても書く予定ではあります。が、既に記事があるので一旦こちらにご案内します...! → TypeScript の Interface と Type Alias の違い
参考文献
- 投稿日:2021-03-02T19:45:58+09:00
TypeScriptをなんとなく理解するための記事② ~型を組み合わせる: Union~
この記事は何?
TypeScriptとは何か、何がいいのかを伝えようと頑張った記事の第2弾です!
今回は、型を組み合わせて新たな型を生成する、
Unionについて説明していきます。@ 過去の記事、続編?も合わせて御覧ください!
1. JavaScriptを知っている方がTypeScriptをなんとなく理解するための記事① ~はじめに~
2. TypeScriptをなんとなく理解するための記事② ~型を組み合わせる: Union~← この記事
3. TypeScriptをなんとなく理解するための記事③ ~汎用的な型を作成する: Generics~
4. TypeScriptをなんとなく理解するための記事④ ~構造型~
@ TypeScriptがなんとなく理解できたら、是非インストールして、触ってみてください!
? 【画像で説明】シンプルにTypeScriptを導入して使う方法型の組み合わせとは?
TypeScriptでは、型と型を組み合わせて新しく型を作り上げることが出来ます。
この型の組み合わせの方法は2つあります。
1つは、Union、もう1つは、Genericsです。この記事では、Unionの概要について説明していきます。
※Genericsについては次回の記事で説明しています。
Unionによる型の作成
unionの基本
まずは、Unioinを使わずに型を作ってみます。
型はtype
を利用して、以下のように作成します。type Fish = "sanma";新しく
Fish
型を作成しました。
このFish
型は、文字列(string)のsanma
のみを許容する型です。
そのため、この型を使って以下のように、定数lunch
を定義できます。type Fish = "sanma"; const lunch: Fish = "sanma";
lunch
はFish
型なので、"sanma"
のみ許容します。
つまり、ランチにはサンマしか食べることが出来ません。
実際にlunch
にサンマ以外を定義しようとすると...const lunch: Fish = "iwana"; // タイプ '"iwana"'はタイプ '"sanma"'に割り当てることができません。ts(2322)
Fish
型のlunch
には、"iwana"
を定義することが出来ませんでした。
ランチには、サンマもイワナも食べるので、どちらも許容したいです。
そこで、Union
を利用します。Union
は|
を利用して次のように記述します。type Fish = "sanma" | "iwana"; const lunch: Fish = "iwana";このように
|
を利用してFish
型に"sanma"
,"iwana"
に絞る事ができます。ちなみに、
"sanma"
,"iwana"
以外は許容されません。type Fish = "sanma" | "iwana"; const lunch: Fish = "iwana"; const dinner: Fish = "sanma"; const breakfirst: Fish = "saba"; // タイプ '"saba"'はタイプ 'Fish'に割り当てることができません。もちろん数値も扱うことができます。
type AndroidVersion = 9 | 10 | 11; const myAndroidOsVersion: AndroidVersion = 11;ちょっと発展した型の作成
以上では、明確な文字や数値に限定して、型を作成しました。
ここまで厳格にしなくても、「文字列string
はOK!」「文字列の入った配列string[]
はOK!」ということも出来ます。具体的には、以下のような記述方法です。
type Food = string | string[]; const branch: Food = 'cake'; const nightMeal: Food = ['ramen', 'onigiri', 'potechi']; const theLastSupper: Food = ['ramen', 'onigiri', 1498]; // タイプ「number」はタイプ「string」に割り当てることができません。ts(2322)レオナルド・ダ・ヴィンチ作の最後の晩餐(
theLastSupper
)は、1498年に完成しましたが、これは数値であり、文字列でないのでエラーが起きます。ちなみに、このような
Union
で型を定義した際に便利なのが型のチェックです。以下のように、型のチェックをすることができます。
タイプ 述語 文字列 typeof s === "string"
数値 typeof n === "number"
ブール値 typeof b === "boolean"
未定義 typeof undefined === "undefined"
関数 typeof f === "function"
配列 Array.isArray(a)
これを使って、型によって条件分岐をすることが出来ます。
const healthCheck = (food: Food): string => { if (typeof food === "string") { return `it's OK`; } else { return `it's Bad`; } }; console.log(healthCheck(["ramen", "onigiri", "potechi"])); // it's Badおわりに
今回はUnionを使って、型を結合してみました!
型を組み合わせて、自分だけのユニークな型を作ってみましょう!※ 「そういえば、前回、Interfaceが出てきたけどtypeと何が違うの...?」と思った方もいるかもしれません。今後、この違いに関しても書く予定ではあります。が、既に記事があるので一旦こちらにご案内します...! → TypeScript の Interface と Type Alias の違い
Next: TypeScriptをなんとなく理解するための記事③ ~汎用的な型を作成する: Generics~
参考文献
- 投稿日:2021-03-02T19:07:30+09:00
EslintとPrettierをReactプロジェクトで使用(備忘録)
目的
公式では基本的には非推奨となっているみたいなので、
"eslint-plugin-prettier"を使わずに、Reactで作成したプロジェクトをVSCodeで保存時に
フォーマットの自動整形と構文チェックをする。前提
- node.jsとyarnはインストール済み
npx create-react-app
でプロジェクト作成
(この時、eslint 系パッケージはreact-scriptsに含まれている。yarn.lockで確認。)Typescriptはここでは使用せず
VS Code extensionsにて eslintとprettierを導入済み
(VSCode 拡張用の prettier は、node_modules に prettier がインストールされていれば、そちらを実行するようになっている。ここではCLIでコマンドで実行させずに、エディタ上で自動整理を実行させるために、インストールしておく。)
https://marketplace.visualstudio.com/items?itemName=dbaeumer.vscode-eslint
https://marketplace.visualstudio.com/items?itemName=esbenp.prettier-vscode手順
1,
npx create-react-app sample
2,cd sample
3,yarn add -D eslint prettier eslint-config-prettier
4,yarn run eslint --init
:eslintrc.jsonファイル作成 (質問に答えていきます)
5, 各ファイルを編集 (prettierrc.jsonは作らず、デフォルトのままになってます。)eslintrc.json{ "env": { "browser": true, "es2021": true, "jest": true }, "extends": [ "eslint:recommended", "plugin:react/recommended", "plugin:prettier/recommended", "prettier" //eslintのフォーマットの機能を上書きして機能の競合をなくす ], "parserOptions": { "ecmaFeatures": { "jsx": true }, "ecmaVersion": 12, "sourceType": "module" }, "plugins": ["react","prettier"], "rules": { "react/react-in-jsx-scope": "off", "prettier/prettier": "error" } }settings.json{ *省略 //liner "editor.codeActionsOnSave": { "source.fixAll.eslint": true }, "eslint.alwaysShowStatus": true, "eslint.lintTask.enable": true, //formatter "editor.formatOnSave": true, "[javascript]": { "editor.defaultFormatter": "esbenp.prettier-vscode" }, "[javascriptreact]": { "editor.defaultFormatter": "esbenp.prettier-vscode" }, "[json]": { "editor.defaultFormatter": "esbenp.prettier-vscode" }, "editor.formatOnPaste": true, "prettier.packageManager": "yarn", "javascript.format.enable": false, "files.autoSave": "onFocusChange", }参照
- 投稿日:2021-03-02T15:17:30+09:00
jsxでアポストロフィを使う【eslintreact/no-unescaped-entities】
問題
Reactのjsx内にアプストロフィを含む文字列を記述しようとしたらESLintのエラー(eslintreact/no-unescaped-entities)に引っかかった。
解決方法
文字列の
'(アポストロフィ)
の箇所を'
,‘
,'
,’
のどれかに変換する。<Link href="/user/signUp" variant="body2"> Don't have an account? Sign up // エラー Don't have an account? Sign up // OK Don‘t have an account? Sign up // OK Don't have an account? Sign up // OK Don’t have an account? Sign up //OK </Link>
- 投稿日:2021-03-02T09:31:53+09:00
Material UIをTailwind CSSのスタイルで上書きする方法
結論から言うと、Tailwind CSSの設定ファイルに
important: true
を追記します(公式)。tailwind.config.jsmodule.exports = { . . . variants: { extend: {}, }, plugins: [], + important: true, }こうすることで、className属性に指定したTailwind CSSが既存のスタイルの一部(あるいは全て)を上書きしてくれます。
Material UI便利ですよね。でも、使っているうちに既存のスタイルを少し修正したいときがあります。
例えばAvatarコンポーネントは、画像をいかにもアイコン風な感じに切り取ってくれる点が優秀だと感じていますが、もし既存のサイズより小さくカスタマイズしたい場合次のように書く必要があります。react.tsximport { Avatar, makeStyles, createStyles, Theme, } from "@material-ui/core";react.tsxconst useStyles = makeStyles((theme: Theme) => createStyles({ small: { width: theme.spacing(2), //= '16px' height: theme.spacing(2), //= '16px' } }) );react.tsxconst classes = useStyles(); return ( <Avatar className={classes.small}/> );
Tailwind CSSで書く場合、冒頭の設定を行ったならばこれだけで済みます。
react.tsxreturn ( <Avatar className="w-4 h-4"/> //= 'width: 16px, height: 16px' );なお
important: true
はTailwind CSSで記述した全てのクラスが!important宣言
付きでマークアップされることをtrue
にするものですので注意してください。
- 投稿日:2021-03-02T01:08:05+09:00
Function Component の useEffect 内の Promise 内の関数を spyOn する
- 理論上可能そうだったので、ひたすら試行錯誤してたらできたのでメモがてら
- これを作った目的は API を叩けない状況下で、叩いたことにしてテストを進める方法を調べてたから
- HTTP 通信そのものをモックして、その結果に応じた処理が想定通り走っているかどうかを確認したい
create-react-app
で作成した TypeScript React のプロジェクトにnpm t
を掛けてテストすることを想定してます
- 但し検証用のプロジェクトは @lycolia/ts-boilerplate-generator-cli で作ってます
確認環境
Env Ver react 17.0.1 react-scripts 4.0.2 typescript 4.1.3 確認内容
検証対象
- ページ読み込み時に一回だけ API を蹴ってなんかすることを想定しています
AsyncHookExample.tsximport axios from 'axios'; import { useEffect } from 'react'; export const AsyncHookExample = () => { useEffect(() => { axios .get('https://localhost/') .then((res) => console.log(res)) .catch((err) => console.error(err)); }, []); return <p />; };検証方法
axios
をモックした上で、モック関数のPromise
の解決を待ち、Promise
のコールバックをspyOn
して検査する内容です
- モック関数の
Promise
の解決法を求めるのにハマりましたが、これはfoo.mock.results[0].value
に対してawait expect(foo.mock.results[0].value).resolves
としてやればいけます- 細かいことはソースコードのコメントに書いてます
AsyncHookExample.spec.tsximport { render } from '@testing-library/react'; import axios from 'axios'; import { AsyncHookExample } from './AsyncHookExample'; // `axios` をモックにする jest.mock('axios'); // `axios` のモックを取得 const mockedAxios = axios as jest.Mocked<typeof axios>; // `console.log()` を `spyOn' const spyConsoleLog = jest.spyOn(console, 'log'); // `console.error()` を `spyOn' const spyConsoleError = jest.spyOn(console, 'error'); describe('AsyncHookExample', () => { it('resolve promise in Hook', async () => { // テストに期待する結果 // `axios` はモックなので値は適当 const beResult = { status: 200, data: null, }; // `axios` のモックが `resolve` する値を設定 mockedAxios.get.mockResolvedValue(beResult); // コンポーネントを `render` して `useEffect` を走らせる render(<AsyncHookExample />); // `axios.get()` が呼ばれたことを確認 expect(mockedAxios.get).toBeCalled(); // モックの結果を取得 const testResult = mockedAxios.get.mock.results[0].value; // `reject` された値が期待通りであることを確認 await expect(testResult).resolves.toEqual(beResult); // `useEffect` の中の `Promise` の中にある `console.log()` が呼ばれたことを確認 expect(spyConsoleLog).toBeCalled(); }); it('reject promise in Hook', async () => { // テストに期待する結果 // `axios` はモックなので値は適当 const beResult = { status: 400, data: null, }; // `axios` のモックが `reject` する値を設定 mockedAxios.get.mockRejectedValue(beResult); // コンポーネントを `render` して `useEffect` を走らせる render(<AsyncHookExample />); // `axios.get()` が呼ばれたことを確認 expect(mockedAxios.get).toBeCalled(); // モックの結果を取得 const testResult = mockedAxios.get.mock.results[0].value; // `reject` された値が期待通りであることを確認 await expect(testResult).rejects.toEqual(beResult); // `useEffect` の中の `Promise` の中にある `console.error()` が呼ばれたことを確認 expect(spyConsoleError).toBeCalled(); }); });あとがき
mockResolvedValue
のスコープやらモックのPromise
を解決させるマッチャやら調べるのに手間取りました
- あとはそもそも
Promise
が解決した結果がどこに入るのかとか、兎に角あれこれexpect(mockedAxios.get).toBeCalled()
が通るのはすぐに気づいたので、なら出来るだろうとひたすら調べてました
- とりあえず言えることは Jest のドキュメントが大正義でした、、、
- 投稿日:2021-03-02T01:08:05+09:00
useEffect 内の Promise 内の関数を spyOn する
- 理論上可能そうだったので、ひたすら試行錯誤してたらできたのでメモがてら
- これを作った経緯は API を叩けない状況下で、叩いたことにしてテストを進める方法を調べてたから
axios
そのものをモックして、その結果に応じた処理が想定通り走っているかどうかを確認したいcreate-react-app
で作成した TypeScript React のプロジェクトにnpm t
を掛けてテストすることを想定してます
- 但し検証用のプロジェクトは @lycolia/ts-boilerplate-generator-cli で作ってます
確認環境
Env Ver react 17.0.1 react-scripts 4.0.2 typescript 4.1.3 確認内容
検証対象
- ページ読み込み時に一回だけ API を蹴ってなんかすることを想定しています
AsyncHookExample.tsximport axios from 'axios'; import { useEffect } from 'react'; export const AsyncHookExample = () => { useEffect(() => { axios .get('https://localhost/') .then((res) => console.log(res)) .catch((err) => console.error(err)); }, []); return <p />; };検証方法
axios
をモックした上で、モック関数のPromise
の解決を待ち、Promise
のコールバックをspyOn
して検査する内容です
- モック関数の
Promise
の解決法を求めるのにハマりましたが、これはfoo.mock.results[0].value
に対してawait expect(foo.mock.results[0].value).resolves
としてやればいけます- 細かいことはソースコードのコメントに書いてます
AsyncHookExample.spec.tsximport { render } from '@testing-library/react'; import axios from 'axios'; import { AsyncHookExample } from './AsyncHookExample'; // `axios` をモックにする jest.mock('axios'); // `axios` のモックを取得 const mockedAxios = axios as jest.Mocked<typeof axios>; // `console.log()` を `spyOn' const spiedConsoleLog = jest.spyOn(console, 'log'); // `console.error()` を `spyOn' const spiedConsoleError = jest.spyOn(console, 'error'); describe('AsyncHookExample', () => { it('resolve promise in Hook', async () => { // テストに期待する結果 // `axios` はモックなので値は適当 const beResult = { status: 200, data: null, }; // `axios` のモックが `resolve` する値を設定 mockedAxios.get.mockResolvedValue(beResult); // コンポーネントを `render` して `useEffect` を走らせる render(<AsyncHookExample />); // `axios.get()` が呼ばれたことを確認 expect(mockedAxios.get).toBeCalled(); // モックの結果を取得 const testResult = mockedAxios.get.mock.results[0].value; // `reject` された値が期待通りであることを確認 await expect(testResult).resolves.toEqual(beResult); // `useEffect` の中の `Promise` の中にある `console.log()` が呼ばれたことを確認 expect(spiedConsoleLog).toBeCalled(); }); it('reject promise in Hook', async () => { // テストに期待する結果 // `axios` はモックなので値は適当 const beResult = { status: 400, data: null, }; // `axios` のモックが `reject` する値を設定 mockedAxios.get.mockRejectedValue(beResult); // コンポーネントを `render` して `useEffect` を走らせる render(<AsyncHookExample />); // `axios.get()` が呼ばれたことを確認 expect(mockedAxios.get).toBeCalled(); // モックの結果を取得 const testResult = mockedAxios.get.mock.results[0].value; // `reject` された値が期待通りであることを確認 await expect(testResult).rejects.toEqual(beResult); // `useEffect` の中の `Promise` の中にある `console.error()` が呼ばれたことを確認 expect(spiedConsoleError).toBeCalled(); }); });あとがき
mockResolvedValue
のスコープやらモックのPromise
を解決させるマッチャやら調べるのに手間取りました
- あとはそもそも
Promise
が解決した結果がどこに入るのかとか、兎に角あれこれexpect(mockedAxios.get).toBeCalled()
が通るのはすぐに気づいたので、なら出来るだろうとひたすら調べてました
- とりあえず言えることは Jest のドキュメントが大正義でした、、、
- 投稿日:2021-03-02T00:46:25+09:00
Material UIのDrawerでサイドバーを作る最もシンプルな例
はじめに
サイドバーを作ろうと思って、Material UIのDrawerを使おうとしたとき、公式のリファレンスが載せているコードが盛り沢山でどこが最小限なのかわからん!になったので最もシンプルな形を目指してみました。
環境
- Material UI v4.11.3
- react v17.0.1
最もシンプルを目指してみた
import React, {useState} from 'react'; import Drawer from '@material-ui/core/Drawer'; export default function TemporaryDrawer() { const [open, setopen] = useState(false); const toggleOpen=() => { setopen(!open); } return( <> <button onClick={toggleOpen}>hoge</button> <Drawer anchor='left' open={open} onClose={toggleOpen}> <p>hello</p> </Drawer> </> ); }これだけのコードでボタンを押して開いてサイドバー以外をクリックすると閉じるナビゲーションドロワーを実現することができます。
anchor = 'left'
をtop, right, bottomにするとそれぞれ上から、右から、下から出てくるように変更できます。上のコードでの表示をみてみるとこんな感じ
ナビゲーションドロワーの幅を指定する必要はありそうですが、あとは
<Drawer />
の子要素を変更するだけで素敵なナビゲーションドロワーを作れます!!