Использование декоратора MobX @action с асинхронными функциями и. Then

Я использую MobX 2.2.2, чтобы попытаться изменить состояние внутри асинхронного действия. У меня MobX useStrict установлен в true.

@action someAsyncFunction(args) {
  fetch(`http://localhost:8080/some_url`, {
    method: 'POST',
    body: {
      args
    }
  })
  .then(res => res.json())
  .then(json => this.someStateProperty = json)
  .catch(error => {
    throw new Error(error)
  });
}

Я получаю:

Error: Error: [mobx] Invariant failed: It is not allowed to create or change state outside an `action` when MobX is in strict mode. Wrap the current method in `action` if this state change is intended

Нужно ли мне снабжать декоратор @action ко второму оператору? Любая помощь будет оценена.

Ответ 1

Нужно ли мне снабжать декоратор @action ко второму оператору? Любая помощь будет оценена.

Это довольно близко к фактическому решению.

.then(json => this.someStateProperty = json)

должен быть

.then(action(json => this.someStateProperty = json))

Имейте в виду, что action можно вызвать многими способами, которые не являются исключительными для @action. Из документов в действии:

  • action(fn)
  • action(name, fn)
  • @action classMethod
  • @action(name) classMethod
  • @action boundClassMethod = (args) => { body }
  • @action(name) boundClassMethod = (args) => { body }

- все допустимые способы пометить функцию как действие.

Здесь контейнер, демонстрирующий решение: http://jsbin.com/peyayiwowu/1/edit?js,output

mobx.useStrict(true);
const x = mobx.observable(1);

// Do async stuff
function asyncStuff() {
  fetch('http://jsonplaceholder.typicode.com/posts')
    .then((response) => response.json())
    // .then((objects) => x.set(objects[0])) BREAKS
    .then(mobx.action((objects) => x.set(objects[0])))
}

asyncStuff()

Что касается причины вашей ошибки на самом деле, я предполагаю, что верхний уровень @action не рекурсивно украшает любые функции как действия внутри функции, которую он украшает, то есть ваша анонимная функция, переданная в ваше обещание, на самом деле не была action.

Ответ 2

В дополнение к приведенному выше ответу; действительно, action работает только над функцией, которую вы передаете ей. Функции в then выполняются в отдельном стеке и должны быть распознаны как отдельные действия.

Обратите внимание, что вы также можете дать своим действиям имя, чтобы вы могли легко распознать их в devtools, если вы их используете:

then(action("update objects after fetch", json => this.someStateProperty = json))