[英]React.js: setState overwriting, not merging
I'm quite new to React.JS and I am in the process of experimenting by building a masonry-style layout.我是 React.JS 的新手,我正在通过构建砖石风格的布局进行实验。
I render each element to the DOM, then I need to loop over each item and apply x and y positions based on the preceding elements.我将每个元素渲染到 DOM,然后我需要遍历每个项目并根据前面的元素应用 x 和 y 位置。
The initial model looks like this:初始模型如下所示:
[
{
"title": "The Forrest",
"description": "some cool text",
"imgSmallSrc": "/img/img4-small.jpg",
"imgAlt": "Placeholder image",
"tags": [
"Design",
"Mobile",
"Responsive"
],
"date": 1367154709885,
"podStyle": {
"width": 253
}
}
]
(I've only shown one item to keep things short). (为了简短起见,我只展示了一项)。
Once I complete the loop and have my x and y data I want to apply this to the podStyle
object.完成循环并获得 x 和 y 数据后,我想将其应用于
podStyle
对象。 I call setState()
with the following data:我使用以下数据调用
setState()
:
[
{
"podStyle": {
"x": 0,
"y": 0,
"height": 146,
"width": 253
}
}
]
This seems to remove all current data from the model and leave me with just the podStyle
data.这似乎从模型中删除了所有当前数据,而只剩下
podStyle
数据。 Am I misunderstanding how this merge works?我误解了这种合并的工作原理吗?
Thanks in advance for any help!在此先感谢您的帮助!
If your state is an object:如果您的状态是一个对象:
getInitialState: function() {
return { x: 0, y: 0 };
}
you can use setState
to set individual keys on that object:您可以使用
setState
在该对象上设置单个键:
this.setState({ x: 1 }); // y still == 0
React does no intelligent merging of your state; React 不会智能合并您的状态; for example, this does not work:
例如,这不起作用:
getInitialState: function() {
return {
point: { x: 0, y: 0 },
radius: 10
};
}
this.setState({point: {x: 1}});
// state is now == {point: {x: 1}, radius: 10} (point.y is gone)
[Edit] [编辑]
As mentioned by @ssorallen, you can use the immutability helpers to get the effect you're after:正如@ssorallen 所提到的,您可以使用不变性助手来获得您想要的效果:
var newState = React.addons.update(this.state, {
point: { x: {$set: 10} }
});
this.setState(newState);
See this JSFiddle for an example: http://jsfiddle.net/BinaryMuse/HW6w5/以这个 JSFiddle为例: http : //jsfiddle.net/BinaryMuse/HW6w5/
The merging is shallow, so
this.setState({point})
leaves (ed: this.state.radius) intact, but completely replaces (ed: this.state.point).合并是浅的,所以
this.setState({point})
使 (ed: this.state.radius) 完好无损,但完全取代了 (ed: this.state.point)。https://facebook.github.io/react/docs/state-and-lifecycle.html#state-updates-are-merged
https://facebook.github.io/react/docs/state-and-lifecycle.html#state-updates-are-merged
To offer an ES7+ perspective on the answers already given, using transform-object-rest-spread instead of Object.assign()
:为了对已经给出的答案提供 ES7+ 观点,使用transform-object-rest-spread而不是
Object.assign()
:
class MyComponent extends React.Component {
state = {
point: {
x: 0,
y: 0,
},
radius: 10,
}
handleChange = () => {
this.setState((prevState, props) => ({
point: {
// rest operator (...) expands out to:
...prevState.point, // x:0, y:0,
y: 1, // overwrites old y
},
// radius is not overwritten by setState
}));
}
render() {
// omitted
}
}
.babelrc (also requires transform-class-properties from babel preset stage 2) .babelrc(还需要来自 babel 预设阶段 2 的transform-class-properties )
{
"presets": ["es2015", "stage-2", "react"],
"plugins": ["transform-object-rest-spread"],
}
As @sheljohn points out (thanks!), referring to this.state
inside setState
is unreliable:正如@sheljohn 指出的(谢谢!),在
setState
引用this.state
是不可靠的:
Because
this.props
andthis.state
may be updated asynchronously, you should not rely on their values for calculating the next state.因为
this.props
和this.state
可能会异步更新,所以你不应该依赖它们的值来计算下一个状态。...
...
To fix it, use a second form of
setState()
that accepts a function rather than an object.要修复它,请使用接受函数而不是对象的第二种形式的
setState()
。 That function will receive the previous state as the first argument, and the props at the time the update is applied as the second argument该函数将接收先前的状态作为第一个参数,并将应用更新时的 props 作为第二个参数
https://reactjs.org/docs/state-and-lifecycle.html#state-updates-may-be-asynchronous
https://reactjs.org/docs/state-and-lifecycle.html#state-updates-may-be-asynchronous
Something like:就像是:
getInitialState: function() {
return {
something: { x: 0, y: 0 },
blah: 10
};
}
var state = Object.assign(this.state, {
something: Object.assign(this.state.something, { y: 50 }),
});
this.setState(state);
Would be better if it was recursive/deep rather than hard coding the tree, but I will leave that up to the reader :)如果它是递归/深度而不是对树进行硬编码会更好,但我会将其留给读者:)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.