如果您的商店中有observable
列表:
@obserable public Claimslist: IClaim[] = [];
其中IClaim
是接口,claims
是IClaim
对象的数组
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()
并具有隐藏的输入就不会更改?
答案 0 :(得分:1)
Mobx observable
仅观察浅值。意思是说我有@observable claims[]
,然后claims[0] = something
将触发更新,而claims[0].foo = bar
将不会(docs)。要解决此问题,您需要通过在foo
对象上添加@observable foo
使claim
也可观察。
请考虑以下示例。注意Claim1
和Claim2
之间的区别。组件完全相同,但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;
...