My context looks like this:
class AuthStoreClass {
authUser = null
constructor() {
makeAutoObservable(this)
}
login = async (params) => {
const { data: { data: authUser } } = await loginUser(params)
this.authUser = authUser
}
}
const AuthStoreContext = React.createContext(null);
export const authStoreObject = new AuthStoreClass()
export const AuthStoreProvider = ({ children }: any) => {
return <AuthStoreContext.Provider value={authStoreObject}>{children}</AuthStoreContext.Provider>;
};
export const useAuthStore = () => {
return React.useContext(AuthStoreContext);
};
And I am using the context somewhere else in a component:
const LoginPage = observer(() => {
const authStore = useAuthStore()
...
authStore.login(...)
The last line reports the following warning:
[MobX] Since strict-mode is enabled, changing (observed) observable values without using an action is not allowed. Tried to modify: AuthStoreClass@1.authUser
Everything works as expected. How can I fix this issue?
Your login
function is async
and you need to use runInAction
inside, or handle result in a separate action, or use some other way of handling async actions:
import { runInAction, makeAutoObservable } from "mobx"
class AuthStoreClass {
authUser = null
constructor() {
makeAutoObservable(this)
}
login = async (params) => {
const { data: { data: authUser } } = await loginUser(params)
// Wrap all changes with runInAction
runInAction(() => {
this.authUser = authUser
})
// or do it in separate function
this.setUser(authUser)
}
// This method will be wrapped into `action` automatically by `makeAutoObservable`
setUser = (user) => {
this.authUser = user
}
}
That is because, citing the docs, every step ("tick") that updates observables in an asynchronous process should be marked as action. And the code before the first await
is in a different "tick" than the code after await
.
More about async actions (you can even use generators!): https://mobx.js.org/actions.html#asynchronous-actions
In MobX version 6 actions are enforced by default but you can disable warnings with configure
method:
import { configure } from "mobx"
configure({
enforceActions: "never",
})
But be careful doing it though, the goal of enforceActions
is that you don't forget to wrap event handlers and all mutations in an action
. Not doing it might cause extra re-runs of your observers. For example, if you changing two values inside some handler without action then your component might re-render twice instead of once. makeAutoObservable
wraps all methods automatically but you still need to handle async
methods and Promises
manually.