MobXとReactの統合について
mobx-react-lite
ライブラリから提供されるobserver
を使うことで、必要な変更があった場合にのみ再レンダリングされる
基本的な使い方は以下
import React from "react" import ReactDOM from "react-dom" import { makeAutoObservable } from "mobx" import { observer } from "mobx-react-lite" class Timer { secondsPassed = 0 constructor() { makeAutoObservable(this) } increaseTimer() { this.secondsPassed += 1 } } const myTimer = new Timer() const TimerView = observer(({ timer }) => <span>Seconds passed: {timer.secondsPassed}</span>) ReactDOM.render(<TimerView timer={myTimer} />, document.body) setInterval(() => { myTimer.increaseTimer() }, 1000)
timer.secondsPassed
が監視対象になっており、 変更されるとコンポーネントが自動的に再レンダリングされる
配列もオブジェクトの要素の変更も監視しており、todos[0].author.displayName
のような深いパラメータに対しても検知する
主なポイント
外部の状態管理に利用できる
observerは外部状態を、propsとして渡すことも、グローバル変数として使うことも、ReactContextで使用することも可能
ReactContextで使用する例は以下
import {observer} from 'mobx-react-lite' import {createContext, useContext} from "react" const TimerContext = createContext<Timer>() const TimerView = observer(() => { // Grab the timer from the context. const timer = useContext(TimerContext) // See the Timer definition above. return ( <span>Seconds passed: {timer.secondsPassed}</span> ) }) ReactDOM.render( <TimerContext.Provider value={new Timer()}> <TimerView /> </TimerContext.Provider>, document.body )
ローカルな状態管理に利用できる
ローカルな状態としてuseState
で利用可能
import { observer } from "mobx-react-lite" import { useState } from "react" const TimerView = observer(() => { const [timer] = useState(() => new Timer()) return <span>Seconds passed: {timer.secondsPassed}</span> })
クラスを使用する代わりに、監視可能なオブジェクトを直接作成することもできる
import { observer } from "mobx-react-lite" import { observable } from "mobx" import { useState } from "react" const TimerView = observer(() => { const [timer] = useState(() => observable({ secondsPassed: 0, increaseTimer() { this.secondsPassed++ } }) ) return <span>Seconds passed: {timer.secondsPassed}</span> }) ReactDOM.render(<TimerView />, document.body)
上を簡潔に書くためのuseLocalObservable
というフックも用意されている
import { observer, useLocalObservable } from "mobx-react-lite" const TimerView = observer(() => { const timer = useLocalObservable(() => ({ secondsPassed: 0, increaseTimer() { this.secondsPassed++ } })) return <span>Seconds passed: {timer.secondsPassed}</span> }) ReactDOM.render(<TimerView />, document.body)
ただ、React Suspense などのメカニズムの一部の機能が使用できなくなる可能性があるためuseStateが使えるところは使った方が良い