MobX State Tree generator does not allow modified state in a successful promise?

4.4k Views Asked by At

Via the code following I get this error:

error: Error: [mobx-state-tree] Cannot modify 
'AuthenticationStore@<root>', the object is protected and can only be 
modified by using an action.

the code (generator) in question:

.model('AuthenticationStore', {
    user: types.frozen(),
    loading: types.optional(types.boolean, false),
    error: types.frozen()
  })
  .actions(self => ({
    submitLogin: flow(function * (email, password) {
      self.error = undefined
      self.loading = true
      self.user = yield fetch('/api/sign_in', {
        method: 'post',
        mode: 'cors',
        headers: {
          'Content-Type': 'application/json',
        },
        body: JSON.stringify({
          'user' : {
            'email': email,
            'password': password
          }
        })
      }).then(res => {
        return res.json()
      }).then(response => {
        self.loading = false // the error happens here!
        return response.data
      }).catch(error => {
        console.error('error:', error)
        // self.error = error
      })
    }), ...

The question: is this not permitted in a generator, is there a better way to update this particular state or does it need to be wrapped by a try/catch?

As always thanks is advance for any and all feedback!

1

There are 1 best solutions below

1
On BEST ANSWER

The problem is you're calling then on the Promise returned by fetch(), and the function you pass to then is not an action. Note that functions that run within an action (or flow) do not count as the action itself.

Since you're using yield, you don't need to call then or catch on the Promise returned by fetch(). Instead, wrap it in a try/catch:

submitLogin: flow(function* (email, password) {
  self.error = undefined;
  self.loading = true;
  try {
    const res = yield fetch('/api/sign_in', {
        method: 'post',
        mode: 'cors',
        headers: {
          'Content-Type': 'application/json',
        },
        body: JSON.stringify({
          'user' : {
            'email': email,
            'password': password
          }
        })
    });
    const response = yield res.json();
    self.loading = false;
    self.user = response;
  } catch(error) {
    console.log('error: ', error);
    self.error = error;
  }
}