简体   繁体   English

ReactJS mobx - 不更新可观察数组

[英]ReactJS mobx - does not update observable array

If you have an observable list in your store:如果您的商店中有一个observable列表:

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

where IClaim is an interface, claims is an array of IClaim objects其中IClaim是一个接口, claims是一个IClaim对象数组

IClaim contains a varaible in its object called moveOutDate Each claim object has id variable. IClaim在其对象中包含一个名为moveOutDate变量。每个声明对象都有id变量。

And now you want to update or get that variable by the claim id现在您想通过claim ID 更新或获取该变量

So you have 2 functions:所以你有两个功能:

Get得到

  /**
   * 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;
  }

Set

  /**
   * 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, but now when you use getMoveOutDateById at first in your render it works and renders the date, but once you call setMoveOutDate onUpdate of the date component, the render won't update, but the store will update and you can only see changes if you refresh the page. getMoveOutDateById ,但是现在当您首先在render使用getMoveOutDateById时,它会起作用并渲染日期,但是一旦您调用日期组件的setMoveOutDate onUpdate ,渲染将不会更新,但存储将更新,您只能看到更改你刷新页面。

Now I managed to solve it, by doing:现在我设法通过执行以下操作来解决它:

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

and adding an hidden input of Claimslist:并添加 Claimslist 的隐藏输入:

const {Claimslist} = this.props.claimsStore;

and

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

Why does it happen, if the whole object is obserable and is wrapped with @action why doesn't it change without using slice() and having an hidden input?为什么会发生,如果整个对象是可obserable并且用@action包裹,为什么不使用slice()和隐藏输入它不会改变?

Mobx observable only observes shallow values. Mobx observable只观察浅层值。 Meaning lets say I have @observable claims[] then claims[0] = something will trigger an update but claims[0].foo = bar will not (docs) .意思是说我有@observable claims[]然后@observable claims[] claims[0] = something会触发更新,但@observable claims[] claims[0].foo = bar不会(docs) To fix this you need to make foo also observable by adding @observable foo on claim object.要解决此问题,您需要通过在claim对象上添加@observable foo来使foo也可观察。

Consider the following example.考虑以下示例。 Notice the difference between Claim1 and Claim2 .注意之间的差异Claim1Claim2 The components are exactly same yet ClaimView2 will update and ClaimView1 will not.组件完全相同,但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")
);


Update:更新:

Here's a demo for the solution I gave in the comments这是我在评论中给出的解决方案的演示

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")
);

It is not exactly the same, missing @observable, it will be the same if:它不完全相同,缺少@observable,如果:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM