0

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 = []
      }
    },
  }
}
meowzart
  • 75
  • 1
  • 8

1 Answers1

1

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

Danila
  • 15,606
  • 2
  • 35
  • 67
  • Well for the most part I have just watched some youtube tutorials before and most people have code similar to mine. Relatively new tutorials as well. Right now I am parsing the createCurrencyStore to useLocalStore when I create my store. Only reason I waned to separate the actions into a different file would be to avoid having one really big file by separating some of the logic. Also I am comming from redux so it's how I am used to doing things.Thank you for your response I will look at the example and refactor my code tomorrow. – meowzart Nov 07 '20 at 21:14
  • 1
    `useLocalStore` is a react hook, you only really want to use for, well, local stores inside component. For application wide store you don't need it, instead it is better to just use default mobx tools like `makeAutoObservable `. What warning you have though? I thought it was about actions, but if you are using `useLocalStore` then all your methods will be wrapped in actions automatically and there should be no warning. – Danila Nov 07 '20 at 21:20
  • using it to create my store before parsing it as a value to my provider. If you are interested you can take a better look at my code here: https://github.com/nikulasoskarsson/currency-converter-app – meowzart Nov 07 '20 at 21:29
  • Tried wrapping my return inside makeAutoObservable but still getting the warning: https://imgur.com/a/EIsylGD – meowzart Nov 08 '20 at 09:09
  • I've updated my answer with how to handle async actions – Danila Nov 08 '20 at 10:39
  • Oh awesome! Thanks for all your help. I will check out the docs better for sure :) – meowzart Nov 08 '20 at 15:47