meowzart
meowzart

Reputation: 85

How to define an action in a mobx store using mobx-react?

Have been following a few tutorials on youtube and have pretty much never seen anyone explicitly define an action that mutates the state they just throw in into the store. I have been doing the same and while it works a 100% it throws a warning on react native. Just wondering how you could define that something is an action and maybe if someone has a good way to separate the actions into a different file. Here is my store.

export function createCurrencyStore() {
  return {
    currencies: [
      'AED',
      'ARS',
      'AUD',
    ],
    selectedCurrencyFrom: 'USD',
    selectedCurrencyTo: 'EUR',
    loading: false,
    error: null,
    exchangeRate: null,
    amount: 1,
    fromFilterString: '',
    fromFilteredCurrencies: [],
    toFilterString: '',
    toFilteredCurrencies: [],

    setSelectedCurrencyFrom(currency) {
      this.selectedCurrencyFrom = currency
    },

    setSelectedCurrencyTo(currency) {
      this.selectedCurrencyTo = currency
    },

    async getExchangeRate() {
      const conn = await fetch(
        `https://api.exchangerate-api.com/v4/latest/${this.selectedCurrencyFrom}`
      )
      const res = await conn.json()
      console.log(res)
      this.exchangeRate = res.rates[this.selectedCurrencyTo]
    },
    setFromFilters(string) {
      this.fromFilterString = string
      if (this.fromFilterString !== '') {
        this.fromFilteredCurrencies = this.currencies.filter((currency) =>
          currency.toLowerCase().includes(string.toLowerCase())
        )
      } else {
        this.fromFilteredCurrencies = []
      }
    },
    setToFilters(string) {
      this.toFilterString = string

      if (this.toFilterString !== '') {
        this.toFilteredCurrencies = this.currencies.filter((currency) =>
          currency.toLowerCase().includes(string.toLowerCase())
        )
      } else {
        this.toFilteredCurrencies = []
      }
    },
  }
}

Upvotes: 0

Views: 1125

Answers (1)

Danila
Danila

Reputation: 18486

have pretty much never seen anyone explicitly define an action

Well, this is weird because it is a very common thing to only mutate state through actions to avoid unexpected mutations. In MobX6 actions are enforced by default, but you can disable warnings with configure method:

import { configure } from "mobx"

configure({
    enforceActions: "never",
})

a good way to separate the actions into a different file

You don't really need to do it, unless it's a very specific case and you need to somehow reuse actions or something like that. Usually you keep actions and the state they modify together.

I am not quite sure what you are doing with result of createCurrencyStore, are you passing it to observable? Anyway, the best way to create stores in MobX6 is to use makeAutoObservable (or makeObservable if you need some fine tuning). So if you are not using classes then it will look like that:

import { makeAutoObservable } from "mobx"

function createDoubler(value) {
    return makeAutoObservable({
        value,
        get double() {
            return this.value * 2
        },
        increment() {
            this.value++
        }
    })
}

That way every getter will become computed, every method will become action and all other values will be observables basically.

More info in the docs: https://mobx.js.org/observable-state.html

UPDATE:

Since your getExchangeRate function is async then you need to use runInAction inside, or handle result in separate action, or use some other way of handling async actions:

import { runInAction} from "mobx"


 async getExchangeRate() {
      const conn = await fetch(
        `https://api.exchangerate-api.com/v4/latest/${this.selectedCurrencyFrom}`
      )
      const res = await conn.json()

      runInAction(() => {
        this.exchangeRate = res.rates[this.selectedCurrencyTo]
      })
      // or do it in separate function
      this.handleExchangeRate(res.rates[this.selectedCurrencyTo])
    },

More about async actions: https://mobx.js.org/actions.html#asynchronous-actions

Upvotes: 1

Related Questions