@actionの他に@action.bound があることを知ったので違いを調べた
@action と @action.bound の違い
結論からいうとthisのバインドされるかされないかである
@action と @action.boundはどちらも、MobXで状態を変更するメソッドを定義するために使用するが、@actionはthisのバインドは自動で行われない
一方、 @action.boundはメソッドのthisを自動的に現在のインスタンスにバインドする
@actionの場合
import { observable, action } from 'mobx'; class Store { @observable count = 0; @action increment() { this.count++; } } const store = new Store(); store.increment(); // OK const incrementFn = store.increment; incrementFn(); // エラー: thisがundefinedになる
@action.boundの場合
import { observable, action } from 'mobx'; class Store { @observable count = 0; @action.bound increment() { this.count++; } } const store = new Store(); const incrementFn = store.increment; incrementFn(); // OK: thisが正しくバインドされている
主な違いまとめ
| 特徴 | @action |
@action.bound |
|---|---|---|
thisのバインド |
自動バインドされない | 自動的にインスタンスにバインドされる |
| 他のコンテキストで使用 | thisが失われる可能性がある |
thisを意識せずに使用可能 |
| 典型的な用途 | インスタンス内で直接使用するメソッド | コールバックやイベントハンドラでの使用 |
どちらを使うべきか?
@action- メソッドをクラス内部で直接使用する場合
thisのバインドが不要な場合
@action.bound- メソッドをイベントハンドラやコールバックとして使用する場合
thisのコンテキストが重要な場合
特に、ReactコンポーネントでMobXストアのアクションを使うときに、ハンドラとして渡すケースでは@action.boundが良い
理由として、通常のクラスメソッドをReactのイベントハンドラとして渡すと、thisが失われる
これはJavaScriptの関数がデフォルトでは実行時のコンテキストに依存するため
なので、以下のようにイベントハンドラとして渡すのは@action.boundが良い
import React from 'react'; import { observable, action } from 'mobx'; import { observer } from 'mobx-react'; class Store { @observable count = 0; @action.bound increment() { this.count++; } } const store = new Store(); const Counter = observer(() => { return ( <button onClick={store.increment}> {store.count} </button> ); }); export default Counter;