当 setState 与 class 的对象实例发生反应时会发生什么
what happens in react when setState with object instance of a class
我有这个fiddle
let m = new Mine();
this.setState(m, () => {
console.log('1:', m instanceof Mine, m.x, m.meth);
// => 1: true 123 function meth() {}
console.log('2:', this.state instanceof Mine, this.state.x, this.state.meth);
// => 2: false 123 undefined
});
如您所见,我创建了一个 Mine class 实例,然后使用该实例在 React 组件中设置状态。
我希望 this.state 完全包含该实例,但是虽然在构造函数中设置的实例属性可用,但我无法访问该实例的任何 class 方法。
fiddle 中的测试表明 this.state 不是 class 我的实例。
是否有人了解发生了什么或者这是意外行为?
在这种情况下使用 replaceState
,应该可以。
经过更多调查,我发现了发生这种情况的原因。
react 的函数 _processPendingState 使用 Object.assign 设置新状态,因此由于目标对象是一个新对象(不同于传递给 setState 的对象),新状态失去了作为实例的质量的 "Mine" class.
并且由于 Object.assign 仅将自己的可枚举属性从源复制到目标,因此新状态也不会有 class 方法。
如果在 fiddle 中我们替换行...
let m = new Mine();
与...
let m = {x: 123};
Object.defineProperty(m, 'meth', {
enumerable: false,
get() { return function() {}; }
});
我们仍然没有关于结果状态的 "meth" 属性。即使 "m" 拥有 "meth" 属性 也不可枚举。
最好的解决方案是将方法作为箭头函数显示出来:
class Blah {
constructor() {
// no definition here for surfacedMethod!
}
surfacedMethod = () => {
// do something here
}
}
然后您可以在 setState 中设置此 class 的实例并使用它们的方法,就好像它们是在实例上设置的属性一样。
// other component innards
this.setState(state => ({blah: new Blah()}))
// later
this.state.blah.surfacedMethod(); // this will now work
我有这个fiddle
let m = new Mine();
this.setState(m, () => {
console.log('1:', m instanceof Mine, m.x, m.meth);
// => 1: true 123 function meth() {}
console.log('2:', this.state instanceof Mine, this.state.x, this.state.meth);
// => 2: false 123 undefined
});
如您所见,我创建了一个 Mine class 实例,然后使用该实例在 React 组件中设置状态。
我希望 this.state 完全包含该实例,但是虽然在构造函数中设置的实例属性可用,但我无法访问该实例的任何 class 方法。
fiddle 中的测试表明 this.state 不是 class 我的实例。
是否有人了解发生了什么或者这是意外行为?
在这种情况下使用 replaceState
,应该可以。
经过更多调查,我发现了发生这种情况的原因。
react 的函数 _processPendingState 使用 Object.assign 设置新状态,因此由于目标对象是一个新对象(不同于传递给 setState 的对象),新状态失去了作为实例的质量的 "Mine" class.
并且由于 Object.assign 仅将自己的可枚举属性从源复制到目标,因此新状态也不会有 class 方法。
如果在 fiddle 中我们替换行...
let m = new Mine();
与...
let m = {x: 123};
Object.defineProperty(m, 'meth', {
enumerable: false,
get() { return function() {}; }
});
我们仍然没有关于结果状态的 "meth" 属性。即使 "m" 拥有 "meth" 属性 也不可枚举。
最好的解决方案是将方法作为箭头函数显示出来:
class Blah {
constructor() {
// no definition here for surfacedMethod!
}
surfacedMethod = () => {
// do something here
}
}
然后您可以在 setState 中设置此 class 的实例并使用它们的方法,就好像它们是在实例上设置的属性一样。
// other component innards
this.setState(state => ({blah: new Blah()}))
// later
this.state.blah.surfacedMethod(); // this will now work