Shouldn't useContext() only be used for low frequent updates? (mobx-react-lite)

1.4k Views Asked by At

Almost all examples (even the official documentation) use mobx-react-light in combination with useContext() hook.

However, React, many articles and blog-posts advice to NOT USE useContext() for middle/high frequent updates. Isn't state something which can update very frequenty?

Should one use the package in combination with the hook or will performance issues occur?

1

There are 1 best solutions below

5
On BEST ANSWER

useContext() is only used to get your store value (reference) and this value is not updated frequently, usually you only set your stores once and don't touch it after. When you use actions you only change observable values of your store and not the store itself. So basically Context is only used to pass reference to the store down the tree, after that all the work performed by MobX only.

Example from MobX docs:

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
)

So you pass value of new Timer() to TimerContext.Provider once when you render your app and it will never be changed or updated after that. Even docs says:

Note that we don't recommend ever replacing the value of a Provider with a different one. Using MobX, there should be no need for that, since the observable that is shared can be updated itself.

However, if you don't have SSR or don't test your app, then you don't even need to use Context at all, you can just use global variables/singletons as your stores and it will work perfectly fine.

Example:

// Initialize timer somewhere
export const myTimer = new Timer()

// You can use directly in the same file or import somewhere else
import { myTimer } from './file-with-your-timer'

// No props, `myTimer` is directly consumed from the closure or from another file
const TimerView = observer(() => <span>Seconds passed: {myTimer.secondsPassed}</span>)

ReactDOM.render(<TimerView />, document.body)

Quote from docs:

Using observables directly works very well, but since this typically introduces module state, this pattern might complicate unit testing. Instead, we recommend using React Context instead.

More about best practices with React: https://mobx.js.org/react-integration.html