VSCode拡張を自作する。~ viewに対するtitle menuの設定 ~
はじめに
これは前回の『VSCode拡張を自作する。~ activitybarにオリジナルのアイコンを表示する。~』の続きというか、おまけ記事になります。
activitybarにオリジナルアイコンを設定する方法や、一連の作り方を知りたい方は以前の記事から読んでみてください!
command
の設定
今回は前回記事を参考に、予めactivitybarにオリジナルアイコンを表示させ、viewの表示ができるところまで用意してあります。
今日はここから、タイトル通りviewにmenuを追加していきます。
(contributesは以下の通り。)
// package.json "contributes"部分のみ抜粋 { "contributes": { "views": { "sample-container": [ { "id": "custom-container-id-1", "name": "Custom view1" }, { "id": "custom-container-id-2", "name": "Custom view2" } ] }, "viewsContainers": { "activitybar": [ { "id": "sample-container", "title": "Sample", "icon": "./logo.svg" } ] } } }
まずは、commandsを設定していきます。
commandsも今までと同様に、"contributes"
の中に設定していきます。
設定項目は下記の通りです。
command
: 登録するコマンドの識別子title
: UI上で表示されるコマンド名icon
: (省略可) アイコンでコマンドを表現したい場合に設定します。category
: (省略可) アイコンをカテゴリ分けすることができます。(コマンドパレットにGo: Install/Update Tools
と表示される場合のGo
の部分に当たります。)enablement
: (省略可)コマンドを有効にします。
今回は、view titleにReloadボタンを表示させたいので、iconまで設定します。
{ "contributes": { // ↓↓ 今回設定部分 ↓↓ "commands" :[ { "command": "sampleExt.reload-command", "title": "Reload", "category": "SampleExt", "icon": "$(refresh)" } ], // ↑↑ 今回設定部分 ↑↑ "views": { "sample-container": [ { "id": "custom-container-id-1", "name": "Custom view1" }, { "id": "custom-container-id-2", "name": "Custom view2" } ] }, "viewsContainers": { "activitybar": [ { "id": "sample-container", "title": "Sample", "icon": "./logo.svg" } ] } } }
icon
部分で設定している$(refresh)
はVSCodeに元々用意されているアイコンを参照しています。
他にどんなアイコンがあるのか気になる方は、公式サイトを見てみましょう!
commandの設定はこれで完了です。
menuの登録
次は先ほど、設定したコマンドをmenuに登録していきます。
menuもcontributes
から設定が可能です。
{ "contributes": { "commands" :[ { "command": "sampleExt.reload-command", "title": "Reload", "category": "SampleExt", "icon": "$(refresh)" } ], // ~ 省略 ~ "menus": { "view/title": [ { "command": "sampleExt.reload-command" } ] } } }
今回はtitle menuを設定したいので、view/title
を選択します。
ここで設定可能な項目は、下記の通りです。
command
:commands
タグ配下に設定したコマンドの識別子alt
: (省略可) 代替えコマンドの設定。代替えコマンドを設定する場合は予め、commands
に代替えのコマンドを登録しておく必要があります。group
: (省略可)メニュー項目をグループ分けできます。(navigation
という特殊なグループも存在しますが、これは後述します。)when
: (省略可) 特定の条件に応じて、メニュー表示を制御したい場合に使用します。
UI表示だけ設定するのであれば、これでOKです。
実際に表示すると下記のようにメニューが表示されていることが分かります。
登録したコマンドに関しては、コマンドパレットからも確認することができます。
ただ、ここで物足りないのは、title menuが折りたたまれてしまっている部分です。
せっかくアイコンも設定しているのに、ChromeのReloadボタンのようなアイコンが表示されていません。
こういった場合は、先ほど少しだけ紹介した、navigation
という特殊なグループを設定することで解決ができます。
navigation
は文字通り、Navメニュー専用のグループでこれを設定することで、アイコンが表示されるようになります。
{ "contributes": { "commands" :[ { "command": "sampleExt.reload-command", "title": "Reload", "category": "SampleExt", "icon": "$(refresh)" } ], // ~ 省略 ~ "menus": { "view/title": [ { // 特殊なグループ"navigation"を指定 "command": "sampleExt.reload-command", "group": "navigation" } ] } } }
これを実際に確認してみると....
今度はReloadアイコンが表示されているのを確認できました。
おまけ
navigation
グループを活用することで、Explorerのようなtitle menuを簡単につくることができます。
"contributes": { "commands" :[ { "command": "sampleExt.1addFile-command", "title": "Add File", "category": "SampleExt", "icon": "$(file-add)" }, { "command": "sampleExt.2addFolder-command", "title": "Add Folder", "category": "SampleExt", "icon": "$(file-directory-create)" }, { "command": "sampleExt.3reload-command", "title": "Reload", "category": "SampleExt", "icon": "$(refresh)" }, { "command": "sampleExt.4collapse-command", "title": "Collapse All", "category": "SampleExt", "icon": "$(collapse-all)" } ],, // ~ 省略 ~ "menus": { "view/title": [ { "command": "sampleExt.1addFile-command", "group": "navigation" }, { "command": "sampleExt.2addFolder-command", "group": "navigation" }, { "command": "sampleExt.3reload-command", "group": "navigation" }, { "command": "sampleExt.4collapse-command", "group": "navigation" } ] } } }
ちなみに、sampleExt.1addFile-command
, sampleExt.4collapse-command
のようにコマンドの先頭部分に数字を入れているのは、コマンドの表示順を調整するためです。
title menuの表示はあくまでcommand
名でソートされるため、順番を調整するためには名前つけを意識的に行うか、先頭に数値を入れるなどして調整する必要があります。
まとめ
- title menuを表示するためにはまず
command
を定義する。 - 定義したコマンドを
menus
配下のview/title
に設定する。 - アイコンを表示したい場合は特殊グループ
navigation
を設定する。
ここまではUI表示を定義しただけに過ぎないので、次こそは実際のコマンドを定義する部分に触れていきましょう。
関連記事
Visual Studioで『Custom Project Templates』の作成
はじめに
- はじめに
- 検証環境
- Templateの作り方
- 既存ProjectからTemplateのExport
- オリジナルのテンプレートを配置する
- Error回避Tips
- 自作Templateから新規Project作成
- 既存のテンプレート保存場所
- まとめ
Visual Studioには、元々コンソール アプリ(.NET Core)
や ASP.NET Core Web アプリケーション
など色々なProject Templateが用意されています。
既存のTemplateに加えて、『Custom Project Templates』を追加することもできるため、開発チームや自分用に予め用意しておけば、非常に開発が捗ります!!
今日は『Custom Project Templates』の作り方についてまとめていきます。
検証環境
- Windows10 Pro
- Visual Studio 2019
上記の環境で、検証を行っています。
Templateの作り方
知らないと何となく難しそうなTemplate作成ですが、比較的簡単に作成することができます。主なTemplateの作り方は、次の2通りです。
- 既存ProjectからExportする。
.vstemplate
ファイルを自作する。
特に1. 既存ProjectからExportする。
は非常に簡単で、開発で特定のProjectをテンプレート化したいという場合は、ボタンをクリックするだけでほぼ終わりです。
個人的には、ほとんどの場合が1
の方法で作成しています。
なんでも良いので、適当なProjectをExportしてから、カスタマイズした方が.vstemplate
ファイルのタグを一から入力する必要がなくて、楽だからです。
既存ProjectからTemplateのExport
さっそく、既存ProjectからTemplateを作成していきます。
Visual Studioを開いたら、まずメニューのプロジェクト(P)
を選択します。
プロジェクトを選択するとテンプレートのエクスポート(E)
があるはずなので、それを選択します。
テンプレートのエクスポート(E)
を選択すると出力メニューが開くので、ガイドに沿って進めていきます。
Project Templateを作成する場合は、プロジェクト テンプレート(R)
にチェックが入っていることを確認して、出力対象のProjectを選択します。
今回のサンプルには、TargetProject
しか存在しないので、それを選択します。
テンプレート名
は新規プロジェクト追加時に表示されるテンプレート名のことで、検索にも使用するので分かりやすい名前を付けておきましょう。
また、.NET Frameworkなど特定のフレームワークに依存する場合は、(.NET Framework)
など識別できるようにしておくのがポイントです。
後は完了
をクリックすれば、出力は完了です。
出力したテンプレートは、下記のフォルダに出力されます。
%USERPROFILE%\Documents\Visual Studio 2019\My Exported Templates
.zip
ファイルが確認できれば、出力は完了です。
オリジナルのテンプレートを配置する
完成したProject Templateを配置していきます。オリジナルで作成したものに関しては、User用のフォルダへ配置する必要があります。
(ちなみに、既存ProjectからExportした場合は自動的にUser用フォルダにも出力されます。)
%USERPROFILE%\Documents\Visual Studio 2019\Templates\ProjectTemplates
のフォルダ直下にTemplateを配置していきますが、ここでポイントがあります。
配置する際には、フォルダを.zip圧縮する必要があります。
(展開する必要はありません。)
加えて重要なポイントとして、圧縮したファイルのRootに.vstemplate
ファイルが含まれている必要があります。
先ほど、作成したTemplateにも.vstemplate
ファイルが含まれているのが確認できます。
これで準備完了です。
Error回避Tips
1. User用フォルダへの配置忘れ
ちなみにMy Exported Templates
側の.zip
ファイルを修正して、User用フォルダに配置しない。というミスが良くあります。
あくまで、Templates\ProjectTemplates
配下に配置したものが読み取られるので注意しましょう。
2. 圧縮方法を間違え
先ほど、.zip
ファイルにする必要があるといいましたが、ここにもポイントがあります。
自作したTemplateをフォルダごと圧縮してしまうと、.zip
ファイルはフォルダが入れ子の状態になってしまいます。
あくまで、Rootに.vstemplate
ファイルが含まれている必要があるので注意しましょう。
(圧縮したいファイルやフォルダを全選択した状態で、送る
から圧縮すれば、入れ子にはなりません。)
自作Templateから新規Project作成
それでは最後に、自作TemplateからProjectを作成してみます。 新しいプロジェクトの追加から、先ほどの"SampleExportTemplate (.NET Core)"を検索します。
先ほどの自作Templateが確認できましたね!
後はプロジェクトを作成するだけです。
対象にしたTargetProject
と同じ構成のProjectが作成されたことが確認できました。
既存のテンプレート保存場所
Templateを作成するのであれば、既存Templateに一通り目を通しておくと良いと思います。
下記のフォルダに配置されていますが、くれぐれも壊さないように注意しましょう!!
%ProgramFiles(x86)%\Microsoft Visual Studio\2019\<edition>\Common7\IDE\ProjectTemplates\<Language>\<Locale ID>
まとめ
- 自作Templateを作るのは意外に簡単。特に既存のProjectからのExport。
- 自作Templateを配置する際にミスが多いので注意する。
これだけでも十分に便利ですが、今回の方法だと少し不便な部分があります。
例えば、新規プロジェクト作成の際に入力したプロジェクト名に応じて、ファイル名を変更したい場合などは単にExportするだけでは対応ができません。
次は.vstemplate
を編集して、より便利なTemplateを作成していきます。
VSCode拡張を自作する。~ activitybarにオリジナルのアイコンを表示する。~
はじめに
activitybarに自作拡張機能のアイコンを表示するところで躓いたので、備忘録として残しておきます。
activitybarってどこ?
今回対象になっている『activitybar』は下記の写真のオレンジ色の部分です。
Exploer, Docker拡張といったアイコンが表示されている場所のことを指します。
ここに自作のアイコンを表示させていきます。
(VSCodeのUI各部名称が分からないという方は公式サイトを確認しましょう!!)
activitybarにビューコンテナを登録する
まず、activitybarに自作のアイコンを表示させるためには、ビューコンテナに自作のアイコンの設定を登録する必要があります。
登録するために、contributes.viewsContainers.activitybar
に対して、コンテナの登録を行います。
設定が必要なプロパティは下の3つです。
id
: 作成するコンテナの識別子title
: 表示される名前icon
: 設定するアイコン(package.jsonを基準とする相対パスになります。)
// package.json { "contributes": { "viewsContainers": { "activitybar": [ { "id": "sample-container", "title": "Sample", "icon": "./logo.svg" } ] } } }
id
は、Viewに対してコンテナを登録する際に使用します。
title
はViewに描画された際、アイコンに対してマウスカーソルをhoverさせると画面に表示されたりします。
icon
として表示されるイメージは、50×40四方のブロックの中央に、24×24のサイズで描画されます。推奨ファイルは.svg
ですが、画像ファイルの種類は問いません。
(画像ファイルの種類は問わない。そうですが、私は.svg
以外で試したことはありません。)
これで、コンテナの登録が完了です。
次は登録したコンテナをViewに表示させる作業です。
views
に自作のコンテナを登録する
コンテナの登録はcontributes.views
に対して行います。
先に登録済みの、package.json
を載せておきます。
// package.json { "contributes": { "views": { /* ここで先ほど登録したコンテナのidを指定する。 */ "sample-container": [ // viewの登録はObject配列になっているため、複数登録可能。 { "id": "custom-container-id-1", "name": "custom-container-id-1-name" } ] }, "viewsContainers": { "activitybar": [ { "id": "sample-container", "title": "Sample", "icon": "./logo.svg" } ] } } }
contributes.views
には、すでに組み込みとして"explorer", "debug", "scm"などが用意されていますが、今回は自作のコンテナなので先ほど登録したid
を使用します。
コンテナを設定したら、次にコンテナ起動時(アイコンクリック時)に表示されるview
を定義していきます。
ここで、必須にとなるプロパティはid
, name
です。
id
: view識別子name
: 表示名type
: (省略可)tree
とwebview
のどちからを選択可icon
: (省略可)このアイコンは、Viewの名前が表示できない場合に代わりに表示されます。visibility
: (省略可)collapsed
,visible
,hidden
から選択できます。(ただし、これは初期設定で、その後はユーザー設定に依存する。)when
: (省略可)viewの表示条件を設定できます。contextualTitle
: (省略可)viewがデフォルトのビューコンテナから移動され、追加のコンテキストが必要な場合に使用されます
Jsonの構造からわかる通り、view定義はコンテナの配下に複数定義することができます。
↑でアイコンの設定は完了しているため、これをDebugすると自作アイコンと登録したviewが表示されます。
実験として、viewを2つ定義した場合も見てみましょう。
// package.json { "contributes": { "views": { "sample-container": [ // view 1つ目 { "id": "custom-container-id-1", "name": "custom-container-id-1-name" }, // view 2つ目 { "id": "custom-container-id-2", "name": "custom-container-id-2-name" } ] }, "viewsContainers": { "activitybar": [ { "id": "sample-container", "title": "Sample", "icon": "./logo.svg" } ] } } }
↑の状態で、Debugを開始すると2つのViewを確認することができます。
これで自作アイコンの表示は完了です。
ただ、あくまでも『自作アイコンの表示』までなので、この状態では何の機能もありません。ただ、『アイコンをクリックできるだけ。』の状態です。
実際に使えるものにしていくためには、viewに応じた機能をactivateする必要があります。
まとめ
contributes.viewsContainers.activitybar
に対して自作コンテナを登録する。- 自作のコンテナを
contributes.views
に登録する。 - コンテナを登録する際、viewは複数定義が可能。
VSCode拡張機能『MyCheatsheet for VS Code』 をリリースしました。
はじめに
タイトル通り、『MyCheatsheet for VS Code』 をリリースしました。
リリースしたと言っても今日というわけではなく、昨年10月にこっそりとリリースしています。
ただ、ひっそりリリースしたはいいものの、作った経緯とかをどこにも書いていなかったので、今日はご紹介交えてそこら辺を書いていきたいです。
MyCheatsheet for VS Codeって何?
『Cheatsheet』はカンニングペーパーのことで、カンニング前提の社会人にとっては強い味方ですw
使用頻度の少ないコマンドや、特殊な文法などをまとめておくと検索の手間が減り非常に便利です。
実際にVSCode拡張機能でもいくつかのCheatsheetが公開されており、『Git Cheatsheet』や『Vue Cheatsheet』などがあります。
上のようにCheatsheetをダウンロードして参照するという拡張機能はすでにありましたが、自分でCheatsheetを作るという拡張機能はなかったので、自分で作ろうと思い立って作成したのが、『MyCheatsheet for VS Code』です。
機能紹介
この拡張機能は...
- ワークスペースのRootに
.cheatsheet.md
ファイルが存在する場合。 - ユーザーホームディレクトリに
.cheatsheets
フォルダが存在する場合。
のいずれかで機能します。
『ワークスペースのRootに.cheatsheet.md
ファイルが存在する場合』というのはイメージしやすいかなと思いますが、『ユーザーホームディレクトリに.cheatsheets
フォルダが存在する場合』というのがイメージしにくいかと思います。
端的に言えば、C:\Users\myName\cheatsheets
が存在している場合。このようなケースで機能が有効になります。(Linux, Macであれば、~/.cheatsheets
フォルダが存在している場合です。)
加えてWikiにも記載しましたが、フォルダ構造が重要です。
## windows C:\Users\myName\.cheatsheets | |-- golang | |-- .cheatsheet.md | |-- typescript |-- .cheatsheet.md or ## Linux or mac ~/.cheatsheets | |-- golang | |-- .cheatsheet.md | |-- typescript |-- .cheatsheet.md
上のように、フォルダ名直下に.cheatsheet.md
ファイルが必要になります。
Cheatsheet参照機能
Ctrl + Shift + P(Win, Linux)
もしくはCmd + Shift + P(Mac)
でコマンドパレットを開き、Show Cheatsheet
コマンドを検索します。
ワークスペースのRootに.cheatsheet.md
ファイルが存在する場合は、下のように表示されます。
ホームディレクトリにフォルダが存在する場合には、下記のように表示されます。
後は、参照したいシートを選択すればOKです。
Global Cheatsheet初期化機能
Ctrl + Shift + P(Win, Linux)
もしくはCmd + Shift + P(Mac)
でコマンドパレットを開き、Init GlobalCheatsheetsDirectory
コマンドを検索します。
これはホームディレクトリ初期化コマンドで、ホームディレクトリに.cheatsheets
ディレクトリが存在しない場合は、ディレクトリを作成します。
Cheatsheet追加機能
Ctrl + Shift + P(Win, Linux)
もしくはCmd + Shift + P(Mac)
でコマンドパレットを開き、Add Cheatsheet
コマンドを検索します。
コマンドを選択すると、workspace
とglobal
の2つの選択肢が表示されます。
※ .cheatsheet
ディレクトリが存在しない場合は、global
は表示されません。
workspace
は文字通り、現在VSCodeで開いているワークスペースのRoot直下にシートを作成できます。
リポジトリでシートを共有したい場合などを想定しています。
次にglobal
ですが、これがHomeディレクトリ直下のシートになります。
global
コマンド選択後に、テキストボックスが表示されるので作成したいシートの名前を入力すればシートが作成されます。
Cheatsheet編集機能
Ctrl + Shift + P(Win, Linux)
もしくはCmd + Shift + P(Mac)
でコマンドパレットを開き、Edit Cheatsheet
コマンドを検索します。
参照と同じ形式で、シートの候補が表示されるので、対象のシートを選択することでシートの編集を行うことができます。
今後の機能追加予定
今後のUpdate予定としては、
- Gitと連携してリポジトリ機能を付けていくこと
- GithubへのPush、Cloneをサポート
が目標になるかなと思っています。
人によっては、PCを複数台使っている人もいると思うので、PCへの簡単な共有を考えるとリポジトリ作成が必須になるかなと思っています。
まとめ
- 自作の
Cheatsheet
を作成できるVSCode用の拡張機能。 - リポジトリ管理ができるような機能を追加予定。
- Githubとの連携もできたらいいなぁと模索中。
今後の情報はこの記事のUpdateと更新情報記事でやっていきます!
golangのinit関数は複数回定義できる
はじめに
そのまんまタイトル通りの内容ですw
Github で いくつかgolangのリポジトリをごそごそしている時に、init関数
が1ファイルに対して、複数回定義されているのを発見しました。
Packageの初期化をするための関数という認識だったので、勝手に『1回だけの定義なんだろうな。』と思っていました。お恥ずかしい。
復習も含めて、再度init
関数について調べなおしてみました。
init関数の役割
init関数は特殊な関数で、Packageの初期化を行う際に機能します。
package main import ( "fmt" ) var message string func init() { message = "Hello world" } func main() { fmt.Println(message) }
main
関数実行前の初期化として作用します。
init関数の呼び出し
init
関数は、PackageをImportした際に呼び出されます。
あくまで、『importした際』に呼び出されるのがポイントです。
これを検証するために、下記のような構造のソースコードを用意しました。
src --- main.go | | --- lib1 | | --- lib.go | | --- lib2 | --- lib.go
// /src/lib1/lib.go package lib1 import "fmt" var libName = "lib1" func init() { fmt.Printf("%s init called!!\r\n", libName) } func Func() { fmt.Printf("%s Func Done.\r\n", libName) }
// /src/lib2/lib.go package lib2 import "fmt" var libName = "lib2" func init() { fmt.Printf("%s init called!!\r\n", libName) } func Func() { fmt.Printf("%s Func Done.\r\n", libName) }
Packageに相当する2つのファイルでは、それぞれinit
関数を定義しており、呼び出しのタイミングでConsole上に文字を出力しています。
/src/main.go package main import ( "fmt" "github.com/atEaE/go-sample/lib2" "github.com/atEaE/go-sample/lib1" ) func init() { fmt.Println("main called") } func main() { lib1.Func() lib2.Func() fmt.Println("Hello world!") }
main.go
では、2つのPackageを参照し、それぞれmain
関数の中でPackageの関数を呼び出しています。
ここでは呼び出し順を確認するために、下記ような順番でソースコードを記載しています。
lib2
をImportする.lib1
をImportする.lib1
内のFunc
関数を呼び出す。lib2
内のFunc
関数を呼び出す。
※ VSCode でgofmt
などをしていると保存の際に自動的に並び順がフォーマットされてしまうので、あえてメモ帳などを使って編集しています。
なんとなく(私だけかも知れないが...)、main
関数内の記載順に呼びされそうな感じがしますが、上のコードを実行するとimport順にinit
関数が呼びされることが確認できます。
C:\workspace\sample\go-sample> go run main.go lib2 init called!! lib1 init called!! main called lib1 Func Done. lib2 Func Done. Hello world!
加えて、呼び出し元であるmain.go
のinit
関数はimport終了後に呼びされているのが確認できます。
init関数の定義
init
関数は1ファイルに限らず、Package内で複数回定義ができます。
これについては、公式のドキュメント内の『Package initialization』の項に記載がありました。
Multiple such functions may be defined per package, even within a single source file.
--- このような関数(init関数)は、1つのソースファイル内であっても、パッケージごとに複数定義することができます。--- The Go Programming Language Specification
これも検証用のソースコードを用意しました。
src --- main.go | | --- lib | | --- lib1.go | --- lib2.go
// /src/lib/lib1.go package lib import "fmt" var multiPle1 string func init() { multiPle1 = "lib1 init called" } func init() { fmt.Printf("%s\r\n", multiPle1) } func Hello() { fmt.Print("Hello, ") }
// /src/lib/lib2.go package lib import "fmt" var multiPle2 string func init() { multiPle2 = "lib2 init called" } func init() { fmt.Printf("%s\r\n", multiPle2) } func World() { fmt.Print("World!!") }
lib
Package全体でみると4回のinit
関数が定義されており、各ファイルで2回ずつinit
関数を定義しています。
// /src/main.go package main import "github.com/atEaE/go-sample/lib" func main() { lib.Hello() lib.World() }
このコードの事項結果は下記のようになります。
C:\workspace\sample\go-sample> go run main.go lib1 init called lib2 init called Hello, World!!
初期化処理が煩雑な場合などは、init
を分割した方がメンテナンスが高くなりそうですね。
まとめ
init
関数はimport時に呼び出される。init
関数は1ファイルに限らず, Package毎に複数回定義できる。
React Effect Hooksの覚え書き(基本)
はじめに
Effect Hooks はReact16.8から導入された機能です。
Function Component に対して、Class ComponentのcomponentDidMount
やcomponentWillUnmount
などに相当する処理を実装する場合に使用します。
useEffectを使うたびにcomponentDiMount
とcomponentWillUnmount
の使い分けについて調べている気がしたので、いい加減まとめておきます。
React Component の Lifecycle
React の Lifecycleは大まかにMount
, Update
, Unmount
のサイクルに大別されます。
Mountサイクル
ComponentのインスタンスがDOMに挿入される際のサイクルになります。
Updateサイクル
Props
や State
の変更によって再レンダリングが発生する場合のサイクルになります。
Unmountサイクル
Componentが DOM から削除されるときのサイクルになります。
各VersionにおけるLifecycleを確認する場合には、公式で紹介されているこちらのサイトが便利です。
Effect Hooksが与える副作用
これについては、公式サイトに名言されています。
If you’re familiar with React class lifecycle methods, you can think of useEffect Hook as componentDidMount, componentDidUpdate, and componentWillUnmount combined.
--- Reactクラスのライフサイクルメソッドに慣れている方は、useEffect HookをcomponentDidMount、componentDidUpdate、componentWillUnmountを組み合わせたものと考えることができます。---
Class components における componentDidMount
、componentDidUpdate
、componentWillUnmount
の役割を担うことができます。
公式サイトのサンプルコードを参考に、 componentDidMount
、componentDidUpdate
、componentWillUnmount
を実装したClassとFunction Componentを↓に記載します。
やっていることは少し奇妙ですが、ButtonをClickすることでドキュメントタイトルを切り替えています。
import React from 'react'; import ReactDOM from 'react-dom'; interface Props {} interface State { count: number; } class ClassComponent extends React.Component<Props, State> { constructor(props: Props) { super(props); this.state = { count: 1 } } componentDidMount() { document.title = `Called MountFunc!!`; } componentDidUpdate() { document.title = `Called UpdateFunc!! Cnt = ${this.state.count}`; } componentWillUnmount() { console.log("Called UnmountFunc"); } setCount() { this.setState({ count: this.state.count + 1}); } render() { return ( <div> <h1>Counter</h1> <button onClick={_ => this.setCount()}>Click</button> </div>); } } ReactDOM.render( <React.StrictMode> <ClassComponent /> </React.StrictMode>, document.getElementById('root') );
Class Componentの場合は、componentDidMount
、componentDidUpdate
、componentWillUnmount
をそれぞれ実装することで、Lifecycleに応じて処理を実行することができます。
import React, { useEffect, useState } from 'react'; import ReactDOM from 'react-dom'; interface Props {} function FunctionComponent(props: Props) { const [count, setCount] = useState(1); const initState = 1; useEffect(() => { // componentDidMount & componentDidUpdate if (initState === count) { // componentDidMount専用 document.title = `Called MountFunc!!`; } else { // componentDidUpdate専用 document.title = `Called UpdateFunc!! Cnt = ${count}`; } // 戻り値として、componentWillUnmount return console.log("Called UnmountFunc"); }) return ( <div> <h1>Counter</h1> <button onClick={_ => setCount(count + 1)}>Click</button> </div> ); } ReactDOM.render( <React.StrictMode> <FunctionComponent /> </React.StrictMode>, document.getElementById('root') );
Function Componentの場合は、useEffectだけでcomponentDidMount
、componentDidUpdate
、componentWillUnmount
を表現する必要があります。
componentDidMount
、componentDidUpdate
はuseEffectに引き渡す関数本体に処理を記載することで表現できます。
今回は、MountサイクルとUpdateサイクルを分けて表現したかったので、初期ステータスと比較して呼び出す処理を変更しています。
componentWillUnmount
は、useEffectの戻り値として、関数を返却することで表現することができます。
単純に使うだけであればこれだけOKですが、レンダリング毎のuseEffectの抑制や、Mount & Unmount時のみの実行などチューニングを行う場合には、より複雑になるのでそれはまた次の機会にします。
まとめ
- useEffectを使うことで、関数コンポーネントでも
componentDidMount
、componentDidUpdate
、componentWillUnmount
に相応する作用をもたらすことができる。 - useEffectを使うことで、より細かなチューニングも行うことができる。
参考・引用
意外と大切な開発初期のVSCode準備作業
はじめに
開発初期の準備作業は意外と大変です。
特にプロジェクトに応じてチームが流動的な変わっていく場合には、常に同じような環境で開発できるとは限りません。
『Aのプロジェクトはすんなり開発にJoinできる!』
『Bのプロジェクトは初動が遅いなぁ。』
なんてことが普通にあります。
今日は『開発初期におけるVSCodeの準備作業』と題して、簡単なTipsまとめです。
共有したい設定情報はリポジトリに含める
.vscode
フォルダ配下の設定は、Workspace毎に適用されるため、
.vscode/settings.json
に予めエディタの設定情報を記載してコミットしておくことで、Formatterの設定や、文字コード、Whitespaceのトリミングなどの設定を共有することができます。
{ "editor.tabSize": 2, "editor.insertSpaces": true, "editor.renderWhitespace": "boundary", "editor.rulers": [140], "editor.formatOnSave": true, "editor.defaultFormatter": "esbenp.prettier-vscode", "files.encoding": "utf8", "files.trimTrailingWhitespace": true, "files.insertFinalNewline": true, "files.eol": "\n", "search.exclude": { "public/**": true, "node_modules/**": true } }
ファイルのEncodingやEOLの設定をあらかじめ入れておくことによって、エディタ最適化の時間を短縮することができます。
これだけでもある程度は効果的ですが、特定の拡張機能に対する設定を共有したい場合は別の設定情報も合わせて加える必要があります。
推奨拡張機能を全体で共有する
特定の拡張機能に依存した設定を全体で共有したい場合、推奨拡張をREADME.md
に記載する場合が多いかと思いますが、.vscode/extensions.json
ファイルを使えば、推奨拡張のインストールを開発者に促すことができます。
{ "recommendations": [ "dbaeumer.vscode-eslint", "esbenp.prettier-vscode" ], "unwantedRecommendations": [] }
recommendations
には推奨される拡張機能を。
何らかの理由により推奨されない拡張機能がある場合には、unwantedRecommendations
に拡張機能名を記載します。
後は、Cloneしたソースコードを開けば拡張機能のインストールを促すINFOが表示されます。
INFOが表示されない場合は、Ctrl
+ Shift
+ P
でコマンドレットを開き、Show Recommended Extensions
を入力することで、推奨機能の確認を行うことができます。
まとめ
.vscode/settings.json
をリポジトリにコミットすれば、設定情報は共有できる。- 拡張機能に依存した設定を共有する場合は、
.vscode/extensions.json
も合わせて使うと良い。
初期開発に関わる作業は、特定の人しかやらないことが多いので意外と属人化しやすい部分だなと思っています。 小さなことですが、スムーズな開発にはこういった小さな気づかいや工夫が大切ですね。