MobX没有重新渲染使用@computed的React组件已更改

时间:2018-04-06 21:31:04

标签: reactjs typescript mobx

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()(但不是)。

我想知道的是为什么它不能正常工作?上面的实现似乎有什么不对吗?如果没有,是否有人有任何关于它为什么不起作用的线索?

编辑:除了@observer

之外,我没有任何重载componentShouldUpdate的内容

编辑2:添加了console.log(this.remoteNum)

1 个答案:

答案 0 :(得分:1)

出现问题的路线就在这里:

return this._remoteNum || (this.fetchRemoteNum() && undefined);

原因是,当_remoteNum等于0时,它是假的(因为它将数字转换为布尔值。而0被解释为假)。所以它不会返回数字,但再次调用fetch!通过在每次调用后返回一个新数字,您可以轻松地看到此行为:

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