デコレーター
デコレーターの有効化
長年の変更を経て、ESデコレーターはついにTC39プロセスでStage 3に到達しました。これは、それらが非常に安定しており、以前のデコレーター提案のように破壊的な変更を受けることがないことを意味します。MobXは、この新しい「2022.3/Stage 3」デコレーター構文のサポートを実装しました。最新のデコレーターを使用すると、makeObservable
/ makeAutoObservable
を呼び出す必要がなくなります。
2022.3デコレーターは以下でサポートされています。
- TypeScript(5.0以上。
experimentalDecorators
フラグが有効になっていないことを確認してください)。例となるコミット. - Babelの場合、プラグイン
proposal-decorators
を最新バージョン(現在2023-05
)で有効にしていることを確認してください。例となるコミット.
// tsconfig.json
{
"compilerOptions": {
"experimentalDecorators": false /* or just remove the flag */
}
}
// babel.config.json (or equivalent)
{
"plugins": [
[
"@babel/plugin-proposal-decorators",
{
"version": "2023-05"
}
]
]
}
デコレーターの使用
import { observable, computed, action } from "mobx"
class Todo {
id = Math.random()
@observable accessor title = ""
@observable accessor finished = false
@action
toggle() {
this.finished = !this.finished
}
}
class TodoList {
@observable accessor todos = []
@computed
get unfinishedTodoCount() {
return this.todos.filter(todo => !todo.finished).length
}
}
@observable
を使用する際の新しいaccessor
キーワードの使用に注意してください。これは2022.3仕様の一部であり、最新のデコレーターを使用する場合に必要です。
レガシーデコレーターの使用
TypeScript/Babelのレガシーデコレーターは、言語の公式の一部になることは決してないため、コードベースでそれらを使用することはお勧めしませんが、それでも使用できます。トランスパイルには特定の設定が必要です。
MobXバージョン6以前では、レガシーデコレーターの使用と、observable
、computed
、action
としてマークすることを推奨していました。MobX 6では、これらのデコレーターの使用は推奨されず(代わりに最新のデコレーターまたはmakeObservable
/ makeAutoObservable
を使用する)、現在のメジャーバージョンではまだ可能です。レガシーデコレーターのサポートはMobX 7で削除されます。
import { makeObservable, observable, computed, action } from "mobx"
class Todo {
id = Math.random()
@observable title = ""
@observable finished = false
constructor() {
makeObservable(this)
}
@action
toggle() {
this.finished = !this.finished
}
}
class TodoList {
@observable todos = []
@computed
get unfinishedTodoCount() {
return this.todos.filter(todo => !todo.finished).length
}
constructor() {
makeObservable(this)
}
}
レガシーデコレーターからの移行
レガシーデコレーターから最新のデコレーターに移行するには、次の手順を実行します。
- TypeScriptの設定(またはBabelの同等物)から
experimentalDecorators
フラグを無効化/削除します。 - デコレーターを使用するクラスコンストラクターからすべての
makeObservable(this)
呼び出しを削除します。 - すべての
@observable
(およびバリエーション)のインスタンスを@observable accessor
に置き換えます。
デコレーターの変更/注意点
MobXの2022.3デコレーターはMobX 5デコレーターと非常によく似ているため、使用方法はほとんど同じですが、いくつかの注意点があります。
@observable accessor
デコレーターは、列挙可能ではありません。accessor
には過去には直接的な対応物がありませんでした。これは言語における新しい概念です。ES言語の精神とaccessor
の意味によりよく従うために、それらを非列挙可能な非独自の属性にすることを選択しました。列挙可能性の主なケースは、シリアル化と残りのデストラクチャリングにあるようです。- シリアル化に関しては、すべてのプロパティを暗黙的にシリアル化することは、OOPの世界では理想的ではないため、これは大きな問題ではないようです(
toJSON
を実装するか、serializr
を使用することを代替案として検討してください)。 - 残りのデストラクチャリングに関しては、それはMobXではアンチパターンです。そうすると、すべてのオブザーバブルに(おそらく意図せず)アクセスし、オブザーバーが過度に反応的になります。
- シリアル化に関しては、すべてのプロパティを暗黙的にシリアル化することは、OOPの世界では理想的ではないため、これは大きな問題ではないようです(
@action some_field = () => {}
は、過去も現在も有効な使用方法です。ただし、レガシーデコレーターと最新のデコレーターの間で継承が異なります。- レガシーデコレーターでは、スーパークラスに
@action
でデコレートされたフィールドがあり、サブクラスが同じフィールドをオーバーライドしようとすると、TypeError: Cannot redefine property
がスローされます。 - 最新のデコレーターでは、スーパークラスに
@action
でデコレートされたフィールドがあり、サブクラスが同じフィールドをオーバーライドしようとすると、フィールドをオーバーライドできます。ただし、サブクラスのフィールドは、サブクラスの宣言で@action
でデコレートされていない限り、アクションではありません。
- レガシーデコレーターでは、スーパークラスに
observer
をデコレーターとして使用
mobx-react
のobserver
関数は、関数とデコレーターの両方であり、クラスコンポーネントで使用できます。
@observer
class Timer extends React.Component {
/* ... */
}