Javascript 将MobX@action decorator与异步函数一起使用,然后

Javascript 将MobX@action decorator与异步函数一起使用,然后,javascript,mobx,Javascript,Mobx,我正在使用Mobx2.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.someStatePro

我正在使用Mobx2.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
我是否需要向第二个.then语句提供@action decorator?任何帮助都将不胜感激

我是否需要向第二个.then语句提供@action decorator?任何帮助都将不胜感激

这与实际解决方案非常接近

.then(json => this.someStateProperty = json)
应该是

.then(action(json => this.someStateProperty = json))
请记住,
action
可以通过多种方式调用,而这些方式并不是
@action
独有的。发件人:

  • action(fn)
  • 动作(名称,fn)
  • @action classMethod
  • @action(name)classMethod
  • @action boundClassMethod=(args)=>{body}
  • @action(name)boundClassMethod=(args)=>{body}
都是将函数标记为操作的有效方法

下面是一个箱子,演示解决方案:


至于您的错误实际发生的原因,我猜想顶级的
@action
不会递归地将任何函数修饰为它所修饰的函数中的操作,这意味着传递到承诺中的匿名函数实际上不是一个
操作

来补充上述答案;实际上,
action
只对传递给它的函数起作用。
then
中的函数在单独的堆栈上运行,因此应可识别为单独的操作

请注意,如果您使用以下操作,还可以为这些操作命名,以便在devtools中轻松识别它们:


然后(操作(“获取后更新对象”,json=>this.someStateProperty=json))
注意,在异步方法中,您必须手动在等待某项操作后启动新操作/事务:

@mobx.action async someAsyncFunction(args) {
  this.loading = true;

  var result = await fetch(`http://localhost:8080/some_url`, {
    method: 'POST',
    body: {
      args
    }
  });
  var json = await result.json();
  @mobx.runInAction(()=> {
     this.someStateProperty = json
     this.loading = false;
  });
}
我的偏好 我不喜欢直接使用@mobx.action/runInAction,但总是将其放在
private
方法上。让公共方法调用实际更新状态的私有方法:

public someAsyncFunction(args) {
  this.startLoading();
  return fetch(`http://localhost:8080/some_url`, {
    method: 'POST',
    body: {
      args
    }
  })
  .then(res => res.json())
  .then(this.onFetchResult);
}

@mobx.action 
private startLoading = () => {
   this.loading = true;
}

@mobx.action 
private onFetchResult = (json) => {
   this.someStateProperty = json;
   this.loading = false;
}

投我一票!你的答案是完整的。下次将使用评论作为补充内容。@mweststrate哈哈,我永远不会否决投票。如果您没有使用MobX,我无法回答。递归地将
操作
应用于函数有意义吗?Bluebird在
promisifyAll()
上做了类似的事情,而且非常方便。一开始我认为它不会破坏
userict(true)
的意图。如何在async/await中做到这一点?很好的方法,但是
public
private
只存在于TS中。@VitorLuizC在javascript中是可能的,但它会变得混乱(使私有方法变得混乱)。您需要在构造函数方法作用域中定义私有方法,使用它的公共方法也必须在构造函数本身中创建。
public someAsyncFunction(args) {
  this.startLoading();
  return fetch(`http://localhost:8080/some_url`, {
    method: 'POST',
    body: {
      args
    }
  })
  .then(res => res.json())
  .then(this.onFetchResult);
}

@mobx.action 
private startLoading = () => {
   this.loading = true;
}

@mobx.action 
private onFetchResult = (json) => {
   this.someStateProperty = json;
   this.loading = false;
}