MobX 不重新渲染 React 组件,因为使用的 @computed 已更改
MobX not rerendering React component as used @computed is changed
MobX 似乎不适合我。我基本上有这两个文件:
@inject("apiDepo")
@observer
class Test extends React.Component {
public render() {
return <div>{this.props.apiDepo.remoteNum}</div>
}
}
.
// apiDepo.ts
class apiDepo {
@observable private _remoteNum;
@computed get remoteNum() {
console.log("get")
return this._remoteNum || (this.fetchRemoteNum() && undefined);
}
private async fetchRemoteNum() {
const response = await someFuncThatRequestsARemoteNum();
console.log("set")
this._remoteNum = response.remoteNum || 0;
console.log(this);
console.log("remoteNum", this.remoteNum);
}
}
运行控制台的输出是
> "get"
> "set"
> { _remoteNum: 0, fetchRemoteNum() } // is missing this.remoteNum
> "remoteNum" undefined // should be 0
后面没有了。
据我所知,这是 MobX 应该如何工作的一个非常简单的示例。你得到一个可观察的,它得到更新,应该调用 forceUpdate() (但不是)。
我想知道的是为什么它不能工作?上面的实现有什么不对劲吗?如果没有,有人知道为什么它不起作用吗?
编辑:我没有任何重载 componentShouldUpdate 除了@observer
编辑 2:添加了 console.log(this.remoteNum)
出问题的行是这里:
return this._remoteNum || (this.fetchRemoteNum() && undefined);
原因是,当 _remoteNum 等于 0 时,它是假的(因为它将数字转换为布尔值。0 被解释为假)。所以它不会 return 号码,而是再次调用 fetch!通过在每次通话后 return 拨打一个新号码,您可以轻松地看到此行为:
const response = await new Promise<number>((resolve) => {
window.setTimeout(() => resolve(this._remoteNum++), 1000);
})
要防止此布尔值转换,您需要明确比较该值。
所以解决方案是:
@observable _remoteNum: number;
@computed get remoteNum(): number {
if(this._remoteNum != null) {
return this._remoteNum;
} else {
this.fetchRemoteNum() && undefined;
}
}
private async fetchRemoteNum() {
const response = await new Promise<number>((resolve) => {
window.setTimeout(() => resolve(0), 1000);
})
console.log('updated');
this._remoteNum = response;
}
我建议始终使用 === 或 !== 并且不要让 javascript 隐式地将值转换为 boolean
MobX 似乎不适合我。我基本上有这两个文件:
@inject("apiDepo")
@observer
class Test extends React.Component {
public render() {
return <div>{this.props.apiDepo.remoteNum}</div>
}
}
.
// apiDepo.ts
class apiDepo {
@observable private _remoteNum;
@computed get remoteNum() {
console.log("get")
return this._remoteNum || (this.fetchRemoteNum() && undefined);
}
private async fetchRemoteNum() {
const response = await someFuncThatRequestsARemoteNum();
console.log("set")
this._remoteNum = response.remoteNum || 0;
console.log(this);
console.log("remoteNum", this.remoteNum);
}
}
运行控制台的输出是
> "get"
> "set"
> { _remoteNum: 0, fetchRemoteNum() } // is missing this.remoteNum
> "remoteNum" undefined // should be 0
后面没有了。
据我所知,这是 MobX 应该如何工作的一个非常简单的示例。你得到一个可观察的,它得到更新,应该调用 forceUpdate() (但不是)。
我想知道的是为什么它不能工作?上面的实现有什么不对劲吗?如果没有,有人知道为什么它不起作用吗?
编辑:我没有任何重载 componentShouldUpdate 除了@observer
编辑 2:添加了 console.log(this.remoteNum)
出问题的行是这里:
return this._remoteNum || (this.fetchRemoteNum() && undefined);
原因是,当 _remoteNum 等于 0 时,它是假的(因为它将数字转换为布尔值。0 被解释为假)。所以它不会 return 号码,而是再次调用 fetch!通过在每次通话后 return 拨打一个新号码,您可以轻松地看到此行为:
const response = await new Promise<number>((resolve) => {
window.setTimeout(() => resolve(this._remoteNum++), 1000);
})
要防止此布尔值转换,您需要明确比较该值。
所以解决方案是:
@observable _remoteNum: number;
@computed get remoteNum(): number {
if(this._remoteNum != null) {
return this._remoteNum;
} else {
this.fetchRemoteNum() && undefined;
}
}
private async fetchRemoteNum() {
const response = await new Promise<number>((resolve) => {
window.setTimeout(() => resolve(0), 1000);
})
console.log('updated');
this._remoteNum = response;
}
我建议始终使用 === 或 !== 并且不要让 javascript 隐式地将值转换为 boolean