ReactJS Mobx-不更新可观察数组

时间:2019-03-20 13:37:35

标签: javascript reactjs mobx

如果您的商店中有observable列表:

@obserable public Claimslist: IClaim[] = [];

其中IClaim是接口,claimsIClaim对象的数组

IClaim在其对象中包含一个变量moveOutDate 每个声明对象都有id变量。

现在您想通过claim id更新或获取该变量

所以您有2个功能:

获取

  /**
   * Gets the moveOutDate of a claim by claim ID
   */
  @action getMoveOutDateById = (id: string) => {
    // Get the claim by id
    const claim = this.Claimslist.find((element: IClaim) => element.id === sessionStorage.getItem('claim-id'));
    if (claim) {
      if (!claim.moveOutDate) {
        return undefined;
      }
      return moment(new Date(claim.moveOutDate)).toDate();
    }

    return undefined;
  }

设置

  /**
   * Sets moveOutDate in claim by claim ID
   */
  @action public setMoveOutDate = (id: string, date: Date) => {
    const claim = this.Claimslist.find((element: IClaim) => element.id === id);
    if (claim) {
      claim.moveOutDate = date.toString();
    }
  }

Okey,但是现在当您第一次在getMoveOutDateById中使用render时,它可以工作并呈现日期,但是一旦您调用日期组件的setMoveOutDate onUpdate,渲染不会更新,但是商店会更新,并且只有刷新页面后才能看到更改。

现在,我设法解决了这个问题,

this.Claimslist = this.Claimslist.slice();

并添加一个隐藏的Claimslist输入:

const {Claimslist} = this.props.claimsStore;

<input type="hidden" value={Claimslist} />

为什么会发生这种情况,如果整个对象是obserable并用@action包裹,为什么不使用slice()并具有隐藏的输入就不会更改?

2 个答案:

答案 0 :(得分:1)

Mobx observable仅观察浅值。意思是说我有@observable claims[],然后claims[0] = something将触发更新,而claims[0].foo = bar将不会(docs)。要解决此问题,您需要通过在foo对象上添加@observable foo使claim也可观察。

请考虑以下示例。注意Claim1Claim2之间的区别。组件完全相同,但ClaimView2将更新而ClaimView1将不会更新。 Demo

import React from "react";
import { render } from "react-dom";
import { observable, action } from "mobx";
import { observer } from "mobx-react";

class Claim1 {
  moveOutDate: Date;
  constructor() {
    this.moveOutDate = new Date();
  }
}

@observer
class ClaimsView1 extends React.Component {
  @observable claims: Claim1[] = [
    new Claim1(),
    new Claim1()
  ];

  @action.bound
  updateClaims(){
    this.claims.forEach(claim => {
      claim.moveOutDate = new Date();
    })
  }

  render() {
    return <div>
      <pre>
        {"ClaimsView1 = \n" + JSON.stringify(this.claims, null, "  ")}
      </pre>
      <button onClick={this.updateClaims}> Update </button>
    </div>
  }
}


class Claim2 {
  @observable moveOutDate: Date;
  constructor() {
    this.moveOutDate = new Date();
  }
}

@observer
class ClaimsView2 extends React.Component {
  @observable claims: Claim2[] = [
    new Claim2(),
    new Claim2()
  ];

  @action.bound
  updateClaims(){
    this.claims.forEach(claim => {
      claim.moveOutDate = new Date();
    })
  }

  render() {
    return <div>
      <pre>
        {"ClaimsView2 = \n" + JSON.stringify(this.claims, null, "  ")}
      </pre>
      <button onClick={this.updateClaims}> Update </button>
    </div>
  }
}

render(
  <>
    <ClaimsView1 />
    <ClaimsView2 />
  </>,
  document.getElementById("root")
);


更新:

这是我在评论中提供的解决方案的demo

import React from "react";
import { render } from "react-dom";
import { observable, action } from "mobx";
import { observer } from "mobx-react";

interface IClaim {
  moveOutDate: Date;
}

@observer
class ClaimsView extends React.Component<{claims: IClaim[]}> {
  @observable claims: IClaim[] = this.props.claims.map(claim => observable(claim))

  updateClaims = () => {
    this.claims.forEach(claim => {
      claim.moveOutDate = new Date();
    })
  }

  render() {
    return <div>
      <pre>
        {"claims = \n" + JSON.stringify(this.claims, null, "  ")}
      </pre>
      <button onClick={this.updateClaims}> Update </button>
    </div>
  }
}


render(
  <ClaimsView claims={[
    { moveOutDate: new Date() },
    { moveOutDate: new Date() }
  ]} />,
  document.getElementById("root")
);

答案 1 :(得分:0)

不完全相同,缺少@observable,如果满足以下条件,则将相同:

class Claim1 {
  @observable moveOutDate: Date;
...