Simple React State Management With MobX

July 07, 2021

yarn add mobx mobx-react-lite
// or
npm install mobx mobx-react-lite

Store example - ItemsStore.js

import { makeAutoObservable, runInAction } from 'mobx'

const fakeItems = [
  {
    id: '13asd3',
    title: 'Item 1',
  },
  {
    id: '23asr3',
    title: 'Item 2',
  },
]

export default class ItemsStore {
  items = []
  loading = false
  error = null

  constructor() {
    makeAutoObservable(this)
  }

  get count() {
    return this.items.length
  }

  // async call example
  fetchItems = async () => {
    this.loading = true
    try {
      // simulates data fetching
      const data = await new Promise(resolve => setTimeout(() => resolve(fakeItems), 3000))
      runInAction(() => {
        this.items = data
        this.loading = false
        this.error = null
      })
    } catch (error) {
      runInAction(() => {
        this.error = error
      })
    }
  }
}

Export stores, StoreProvider, and useStore hook - stores.js

import { createContext, useContext } from 'react'

import ItemsStore from './ItemsStore'

export const stores = Object.freeze({
  itemsStore: new ItemsStore(),
})

const storeContext = createContext(stores)
export const StoreProvider = storeContext.Provider
export const useStore = store => useContext(storeContext)[store]

Wrap the app or component/s with StoreProvider - App.js

import React from 'react'
import { StoreProvider, stores } from './stores'
import List from './List'

const App = () => {
  return (
    <StoreProvider value={stores}>
      <List />
    </StoreProvider>
  )
}

export default App

Component example - List.js

import React, { useEffect } from 'react'
import { observer } from 'mobx-react-lite'
import { useStore } from './stores'

const List = () => {
  const { items, loading, fetchItems, count } = useStore('itemsStore')

  useEffect(() => {
    if (!count) fetchItems()
  }, [count, fetchItems])

  return (
    <>
      {loading ? (
        <p>loading...</p>
      ) : (
        <div>
          {items.map(({ id, title }) => (
            <p key={id}>{title}</p>
          ))}
        </div>
      )}
    </>
  )
}

export default observer(List)