MobXは、アプリケーションのステータスを管理するための簡単な戦闘テスト済みソリューションです。 このチュートリアルでは、MobXの基本概念を学びます。 MobXはスタンドアロンライブラリですが、ほとんどの場合、Reactと組み合わせて使用するため、このチュートリアルではこの組み合わせに焦点を当てます。
主なアイデア
状態(state orig。)はすべてのアプリケーションの中心であり、状態の一貫性の欠如のように、タグ付けされた、制御されていないアプリケーションを作成するより速い方法はありません。 または、周囲のローカル変数と矛盾する状態。 したがって、多くの状態管理の決定は、たとえば状態を変更しないなど、変更できる方法を制限しようとしています。 しかし、これは新しい問題を引き起こし、データを正規化する必要があり、参照整合性の保証はなく、プロトタイプ(プロトタイプorig。)などの強力な概念を使用することはほとんど不可能になります。
MobXは、問題の根本に戻ることにより、状態管理を再び簡単にします。状態の不整合を不可能にします。 これを達成するための戦略は非常に簡単です。州から持ち出せるすべてのものを確実に持ち出すようにします。 自動的に。
概念的には、MobXはアプリケーションをスプレッドシートとして処理します(テーブルの操作については、オフィスプログラムを参照してください。約。) 。
まず、アプリケーションの状態状態があります。 アプリケーションのモデルを形成するオブジェクト、配列、プリミティブ、リンクのグラフ。
次に、派生物があります。 通常、これはアプリケーションのステータスデータから自動的に計算できる値です。
反応は Derivationsに非常に似ています。 主な違いは、値を返しませんが、何らかの作業を行うために自動的に開始することです。 これは通常、I / Oに関連付けられています。 彼らは、DOMが更新されるか、ネットワーク要求が時間通りに完了することを確認します。
最後に、 アクションがあります。 アクションは、状態を変更するすべてのものです。 MobXは、アクションによって引き起こされるアプリケーション状態へのすべての変更が、すべての派生物と反応によって自動的に処理されるようにします。 同期して、干渉なし。
シンプルなtodoストア...
十分な理論、それを実際に検討してください。上記を注意深く読むよりもずっと明確です。 独創性のために、非常に単純なTodoリポジトリから始めましょう。 以下は、todoコレクションを管理する非常にシンプルなTodoStoreです。 MobXはまだ関与していません。
import shortid from 'shortid'; class TodoStore { todos = []; get completedTodosCount() { return this.todos.filter( todo => todo.completed === true ).length; } report() { if (this.todos.length === 0) return "<none>"; return `Next todo: "${this.todos[0].task}". ` + `Progress: ${this.completedTodosCount}/${this.todos.length}`; } addTodo(task) { this.todos.push({ id: shortid.generate(), task: task, completed: false, assignee: null }); } } const todoStore = new TodoStore();
todosコレクションを使用してtodoStore
インスタンスを作成しました。 次に、 todoStore
いくつかのオブジェクトをtodoStore
する必要があります。 変更による効果があることを確認するために、変更のtodoStore.report
を呼び出します。
todoStore.addTodo("read MobX tutorial"); console.log(todoStore.report()); todoStore.addTodo("try MobX"); console.log(todoStore.report()); todoStore.todos[0].completed = true; console.log(todoStore.report()); todoStore.todos[1].task = "try MobX in own project"; console.log(todoStore.report()); todoStore.todos[0].task = "grok MobX tutorial"; console.log(todoStore.report());
反応する
これまでのところ、コードに異常はありませんでした。 しかし、 report
明示的に呼び出すのではなく、状態が変化するたびにこのメソッドを呼び出す必要があると宣言した場合はどうでしょうか。 これにより、コードでこのメソッドを呼び出す義務から解放されます。 report
を呼び出した最後の結果が表示されることを確認する必要があります。 しかし、これがどのように行われるか心配する必要はありません。
幸いなことに、これを行うことができるのはMobXです。 状態依存コードを自動的に呼び出します。 したがって、 report
関数は自動的に呼び出されます。 これを実現するには、 TodoStore
がすべての変更を追跡できるように、TodoStoreを監視できる必要があります。 クラスを少し変更しましょう。
また、 completedTodosCount
プロパティはtodos
プロパティから自動的に計算されます。 @observable
および@computed
デコレーターを使用してこれを実現できます。
import shortid from 'shortid'; class ObservableTodoStore { @observable todos = []; @observable pendingRequests = 0; constructor() { mobx.autorun(() => console.log(this.report)); } @computed get completedTodosCount() { return this.todos.filter( todo => todo.completed === true ).length; } @computed get report() { if (this.todos.length === 0) return "<none>"; return `Next todo: "${this.todos[0].task}". ` + `Progress: ${this.completedTodosCount}/${this.todos.length}`; } addTodo(task) { this.todos.push({ id: shortid.generate(), task: task, completed: false, assignee: null }); } } const observableTodoStore = new ObservableTodoStore();
以上です! 一部のプロパティを@observable
としてマークし、MobXが時間とともに変化する可能性があることを認識できるようにしました。 計算は@computed
デコレーターによってタグ付けされ、状態に基づいて計算できることを認識します。
pendingRequests
とassignee
はまだ使用されていませんが、すぐ下に実際の動作が表示されます。 簡潔にするため、すべての例でES6、JSX、およびデコレーターを使用しています。 しかし、心配しないでください。MobXのすべてのデコレータには対応するES5があります。
クラスコンストラクターで、レポートを表示する小さな関数を作成し、 autorun
ラップしました。 1回開始されるリアクションが作成され、その後、関数内の監視対象データが変更されるたびに自動的に再起動します。 report
はtodos
追跡プロパティを使用するため、必要に応じてreport
結果を出力します。
observableTodoStore.addTodo("read MobX tutorial"); observableTodoStore.addTodo("try MobX"); observableTodoStore.todos[0].completed = true; observableTodoStore.todos[1].task = "try MobX in own project"; observableTodoStore.todos[0].task = "grok MobX tutorial";
かっこいいですね。 report
は、中間値が漏洩することなく、自動的に同期的に呼び出されます。 ログへの出力を注意深く調べると、コードの4行目がログの新しいエントリにつながっていないことがわかります。 タスクの名前を変更した結果、 report
は実際には変更されていませんが、内部のデータは変更されているためです。 一方、最初のtodo
name
属性を変更すると、 report
出力の出力が更新されます。これは、 report
結果の出力でname
積極的に使用されるためです。 これは、 todos
配列だけでなく、その中の個々の値も追跡されることを示しています。
Reactをリアクティブにする
さて、これまでのところ、リアクティブな「愚かな」報告を行ってきました。 ここで、同じリポジトリをリアクティブインターフェイスで作成します。 Reactコンポーネント(名前にかかわらず)は、そのままではリアクティブではありません。 mobx-react
@observer
デコレーターは、 mobx-react
render
メソッドをラップすることでこれを修正し、コンポーネントを状態と自動的に同期させます。 これは、概念的には以前にreport
行ったことと変わりません。
次のリストは、いくつかのReactコンポーネントを定義しています。 MobXからは@observer
デコレータのみがあります。 これは、関連するデータが変更されたときに各コンポーネントが再描画されるようにするのに十分です。 setState
を呼び出す必要がsetState
、設定が必要なセレクターまたは高次コンポーネント(Hi Redux)を使用してアプリケーションの一部をサブスクライブする方法を理解する必要がなくなりました。 基本的に、すべてのコンポーネントがスマートになります。 それらが「愚かな」宣言的な方法で定義されていない場合。
@observer class TodoList extends React.Component { render() { const store = this.props.store; return ( <div> { store.report } <ul> { store.todos.map( (todo, idx) => <TodoView todo={ todo } key={ todo.id } /> ) } </ul> { store.pendingRequests > 0 ? <marquee>Loading...</marquee> : null } <button onClick={ this.onNewTodo }>New Todo</button> <small> (double-click a todo to edit)</small> <RenderCounter /> </div> ); } onNewTodo = () => { this.props.store.addTodo(prompt('Enter a new todo:','coffee plz')); } } class TodoView extends React.Component { render() { const todo = this.props.todo; return ( <li onDoubleClick={ this.onRename }> <input type='checkbox' checked={ todo.completed } onChange={ this.onToggleCompleted } /> { todo.task } { todo.assignee ? <small>{ todo.assignee.name }</small> : null } <RenderCounter /> </li> ); } onToggleCompleted = () => { const todo = this.props.todo; todo.completed = !todo.completed; } onRename = () => { const todo = this.props.todo; todo.task = prompt('Task name', todo.task) || ""; } } ReactDOM.render( <TodoList store={ observableTodoStore } />, document.getElementById('reactjs-app') );
次のリストは、データを変更するだけでよいことを示しています。 MobXは、リポジトリの状態からユーザーインターフェイスの関連部分を自動的に計算して更新します。
const store = observableTodoStore; store.todos[0].completed = !store.todos[0].completed; store.todos[1].task = "Random todo " + Math.random(); store.todos.push({ task: "Find a fine cheese", completed: true });
リンクを使用する
これまでに、追跡されたオブジェクト(プロトタイプの有無にかかわらず)、配列、およびプリミティブを作成しました。 しかし、MobXでリンクがどのように処理されるかおもしろいと思うかもしれません。 前のリストで、 todos
assignee
プロパティに気付くかもしれません。 人々を含む別のリポジトリを作成することで別の意味を与えましょう(まあ、それは単なる配列です) 。そして、それらをタスクに割り当てます。
var peopleStore = mobx.observable([ { name: "Michel" }, { name: "Me" } ]); observableTodoStore.todos[0].assignee = peopleStore[0]; observableTodoStore.todos[1].assignee = peopleStore[1]; peopleStore[0].name = "Michel Weststrate";
現在、2つの独立したリポジトリがあります。 1つは人、もう1つはタスクです。 assignee
リポジトリからassignee
プロパティにassignee
を割り当てるには、リンクを介して値を割り当てる必要があります。 これらの値は、 TodoView
によって自動的に取得されます。 MobXを使用すると、コンポーネントを最新の状態に保つためにデータを正規化し、セレクターを書き込む必要がありません。 実際、データの保存場所は問題ではありません。 オブジェクトは「観察可能」ですが、MobXはそれらを追跡します。 実際のJavaScriptリンクも機能します。 MobXは、派生値に関連する場合、それらを自動的に追跡します。
非同期アクション
小さなtodo
アプリケーションのすべてが状態から派生しているため、この状態がどこで変更されるかは関係ありません。 これにより、非同期アクションを簡単に作成できます。
インターフェイスに現在のダウンロードステータスが表示されるpendingRequests
プロパティを更新することから始めます。 ダウンロードが完了したら、 todo
リストを更新pendingRequests
カウンターをpendingRequests
ます。 このコードを上記で見たものと比較して、 pendingRequests
プロパティがどのようにpendingRequests
いるかを確認してください。
observableTodoStore.pendingRequests++; setTimeout(function() { observableTodoStore.addTodo('Random Todo ' + Math.random()); observableTodoStore.pendingRequests--; }, 2000);
mobx-react-devtools
は、任意のMobX + Reactアプリケーションで使用できる開発者ツールを提供します。
おわりに
それだけです! 定型なし。 UIを簡単でシンプルにするシンプルで宣言的なコンポーネント。 状態から完全に更新されました。 これで、アプリケーションでmobx
およびmobx-react
使用を開始する準備が整いました。
今日学んだことの概要:
@observable
デコレータまたはobservable( )
関数を使用して、オブジェクトをMobXで追跡可能にします@computed
デコレータを使用して、状態から値を計算する関数を作成できますautorun
を使用して、監視状態に基づいて関数を自動的に実行します。 これは、ロギングまたはネットワーク要求に適用されます。mobx-react
を使用して、Reactコンポーネントに無効電力を与えます。 それらは自動的に最も効率的に更新されます。 大量のデータがある大規模で複雑なアプリケーションでも。
MobXは状態コンテナーではありません
多くの場合、Reduxの代替としてMobXを使用します。 ただし、これはアーキテクチャや状態コンテナではなく、特定の問題を解決するための単なるライブラリであることに注意してください。 この意味で、上記の例は手に負えないため、メソッドにロジックをカプセル化したり、リポジトリやコントローラーに整理したりするなど、適切なアーキテクチャソリューションを使用することをお勧めします。 または誰かがハッカーニュースで書いたように:
「MobXを使用するということは、コントローラー、ディスパッチャー、アクション、スーパーバイザー、またはその他の形式のデータフロー制御を使用することを意味します。 」
もっと
興味がありますか? ここにいくつかの便利なリンクがあります。