javascript 更新 props 后,this.props 总是 === nextProps / prevProps
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/24989346/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
After updating props, this.props is always === nextProps / prevProps
提问by user2309185
I've got a jsbin for this issue here: http://jsbin.com/tekuluve/1/edit
我在这里有一个关于这个问题的 jsbin:http://jsbin.com/tekuluve/1/edit
In an onClick event I'm removing an element from the model, and re-rendering the app. But strangely, in componentWillReceiveProps() (and componentWillUpdate, and componentDidUpdate too), nextProps is always === to this.props, regardless of what I do.
在 onClick 事件中,我从模型中删除了一个元素,然后重新渲染应用程序。但奇怪的是,在 componentWillReceiveProps()(以及 componentWillUpdate 和 componentDidUpdate)中,nextProps 总是 === 到 this.props,不管我做什么。
/** @jsx React.DOM */
var Box = React.createClass({
render: function() {
return (
<div className="box" onClick={ UpdateModel }>
{ this.props.label }
</div>
);
}
});
var Grid = React.createClass({
componentWillReceiveProps: function(nextProps) {
// WTF is going on here???
console.log(nextProps.boxes === this.props.boxes)
},
render: function() {
var boxes = _.map(this.props.boxes, function(d) {
return (<Box label={ d.number } />);
});
return (
<div className="grid">
{ boxes }
</div>
);
}
});
var model = [
{ number: 1 },
{ number: 2 },
{ number: 3 },
{ number: 4 },
{ number: 5 }
];
function UpdateModel() {
React.renderComponent(
<Grid boxes={ _.pull(model, _.sample(model)) } />,
document.body
);
}
React.renderComponent(
<Grid boxes={ model } />,
document.body
);
I need nextProps to be different to this.props after it has been updated via UpdateModel(), in the componentWillReceiveProps() lifecycle event.
在 componentWillReceiveProps() 生命周期事件中通过 UpdateModel() 更新后,我需要 nextProps 与 this.props 不同。
采纳答案by August Lilleaas
===
will check if it's the same object. It seems that what you're doing is mutating the value that the boxes
property points to.
===
将检查它是否是同一个对象。看来你正在做的是改变boxes
属性指向的值。
回答by Adam Stone
Something like this occurred for me using Flux Stores to store my state in the manner suggested by the official Todo List tutorial (http://facebook.github.io/flux/docs/todo-list.html). For anyone else finding this after following the tutorial, a problem seems to arise in the TodoStore in the getAll() method, because it returns a direct reference to the internal data object:
像这样的事情发生在我使用 Flux Stores 以官方 Todo List 教程(http://facebook.github.io/flux/docs/todo-list.html)建议的方式存储我的状态。对于遵循教程后发现此问题的任何其他人,在 getAll() 方法中的 TodoStore 中似乎出现了问题,因为它返回对内部数据对象的直接引用:
getAll: function() {
return _todos;
}
This seems to breaks the ability of the lifecycle methods like componentDidUpdate(prevProps) to distinguish between the old and new props. I think the reason is that by passing a direct reference to the Store's data object into the views, the state/props effectively change immediately when the Store changes rather than after new values are passed down through the lifecycle methods, so old and new props always contain the same values. This could be solved by passing a copy of the internal data object _todos rather than the object itself,
这似乎打破了像 componentDidUpdate(prevProps) 这样的生命周期方法区分新旧道具的能力。我认为原因是通过将 Store 数据对象的直接引用传递到视图中,当 Store 更改而不是通过生命周期方法传递新值后,状态/道具会立即有效地更改,因此旧的和新的道具总是包含相同的值。这可以通过传递内部数据对象 _todos 的副本而不是对象本身来解决,
for example, when _todos is an object,
例如,当 _todos 是一个对象时,
getAll: function() {
return JSON.parse(JSON.stringify(_todos));
}
If _todos is an array, return _todos.slice() can be used instead.
如果 _todos 是一个数组,则可以使用 return _todos.slice() 代替。
In general, if using a Store to contain state information and call it from your controller-views, it seems advisable to return a copy of the data rather than a reference to the original, since the original will be mutated when state changes occur.
一般来说,如果使用 Store 来包含状态信息并从您的控制器视图中调用它,似乎建议返回数据的副本而不是对原始数据的引用,因为当发生状态更改时原始数据将发生变异。
回答by Federico
You could use Immutable.js. It is a library that Facebook made to work with react/flux. https://facebook.github.io/immutable-js/
你可以使用 Immutable.js。它是 Facebook 用来处理 react/flux 的库。 https://facebook.github.io/immutable-js/
We have been stumped by this a couple of times.
我们被这件事难住了好几次。
shouldComponentUpdate(nextProps) {
return this.props.myObj !== nextProps.myObj
}
Many times, some value inside the myObj object would change. However the above function would return false. The reason being that both this.props.myObj
and nextProps.myObj
were referencing/pointing to the same object.
很多时候,myObj 对象中的某些值会发生变化。但是上面的函数会返回false。原因是this.props.myObj
和nextProps.myObj
都引用/指向同一个对象。
By implementing Immutable.js, the data will always be passed down as clones (instead of referencing the same object, they will actually be separate objects).
通过实现 Immutable.js,数据将始终作为克隆传递(而不是引用同一个对象,它们实际上将是单独的对象)。
It re-enforces flux's uni-directional flow. You will never be able to (accidentally) modify the original data that is being passed into your component (whether as props or from a flux store).
它加强了通量的单向流动。您将永远无法(意外地)修改传递到组件中的原始数据(无论是作为道具还是来自通量存储)。
This also enables you to use a PureRenderMixin – which automatically stops the render if the values of state/props have not changed. This could help with performance.
这也使您能够使用 PureRenderMixin——如果 state/props 的值没有改变,它会自动停止渲染。这可能有助于提高性能。
回答by user3262943
One alternative to implementing Immutable.js is to use object spread operator.
实现 Immutable.js 的一种替代方法是使用对象扩展运算符。
As an example,
举个例子,
suppose you have a variable that you want to modify then do something with
假设您有一个要修改的变量,然后对其进行处理
const obj1 = {a: 1, b: 2}
const obj2 = testObj
obj2.a: 3
// result: obj1 = obj2 = {a:3, b:2}
The original object will be modified. This is because the obj2 variable is essentially just a pointer to obj1 object.
原始对象将被修改。这是因为 obj2 变量本质上只是一个指向 obj1 对象的指针。
Now suppose we use the spread operator instead
现在假设我们改用扩展运算符
const obj1 = {a: 1, b: 2}
const obj2 = {...testObj}
obj2.a: 3
// result: obj1 = {a:1, b:2}, obj2 = {a:3, b:2}
The result of this will be that obj2 is properly updated but obj1 remains untouched. The spread operator effectively create a shallow clone of obj1. I have found the spread operator to be be particularly useful in modifying state in redux reducers. If you set variables equal to state directly and make modify them, it will cause the problem you were experiencing.
这样做的结果是 obj2 已正确更新,但 obj1 保持不变。展开运算符有效地创建了 obj1 的浅层克隆。我发现 spread 运算符在修改 redux reducers 中的状态时特别有用。如果直接将变量设置为 state 并对其进行修改,则会导致您遇到的问题。
回答by hobberwickey
If you don't want to use spreading, you can do this instead. Just change your UpdateModel
function to
如果你不想使用传播,你可以这样做。只需将您的UpdateModel
功能更改为
UpdateModel(){
React.renderComponent(
<Grid boxes={ _.clone(_.pull(model, _.sample(model))) } />, document.body
);
}
Otherwise, the nextProp.boxes object with be the same object as the this.props.boxes object, so any alterations you made to it will be reflected in both.
否则,nextProp.boxes 对象与 this.props.boxes 对象是同一个对象,因此您对它所做的任何更改都将反映在两者中。