使用带有异步函数和 .then 的 MobX @action 装饰器
Using the MobX @action decorator with async functions and .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
我是否需要为第二个 .then 语句提供 @action 装饰器?任何帮助将不胜感激。
Do I need to supply the @action decorator to the second .then statement? Any help would be appreciated.
这与实际解决方案非常接近。
.then(json => this.someStateProperty = json)
应该是
.then(action(json => this.someStateProperty = json))
请记住 action
可以通过多种方式调用,并非 @action
独有。来自 the docs on 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
.
补充以上答案;实际上,action
仅适用于您传递给它的函数。 then
中的函数 运行 在单独的堆栈上,因此应该被识别为单独的操作。
请注意,您还可以为操作命名,以便在使用这些操作时可以在开发工具中轻松识别它们:
then(action("update objects after fetch", json => this.someStateProperty = json))
请注意,在异步方法中,您必须在等待某事后手动启动一个新的 action/transaction:
@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 方法调用实际更新状态的私有方法:
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;
}
我正在使用 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
我是否需要为第二个 .then 语句提供 @action 装饰器?任何帮助将不胜感激。
Do I need to supply the @action decorator to the second .then statement? Any help would be appreciated.
这与实际解决方案非常接近。
.then(json => this.someStateProperty = json)
应该是
.then(action(json => this.someStateProperty = json))
请记住 action
可以通过多种方式调用,并非 @action
独有。来自 the docs on 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
.
补充以上答案;实际上,action
仅适用于您传递给它的函数。 then
中的函数 运行 在单独的堆栈上,因此应该被识别为单独的操作。
请注意,您还可以为操作命名,以便在使用这些操作时可以在开发工具中轻松识别它们:
then(action("update objects after fetch", json => this.someStateProperty = json))
请注意,在异步方法中,您必须在等待某事后手动启动一个新的 action/transaction:
@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 方法调用实际更新状态的私有方法:
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;
}