简体   繁体   English

React.js:setState 覆盖,而不是合并

[英]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"],
}

Updated 2018-04-22 2018-04-22 更新

As @sheljohn points out (thanks!), referring to this.state inside setState is unreliable:正如@sheljohn 指出的(谢谢!),在setState引用this.state是不可靠的:

Because this.props and this.state may be updated asynchronously, you should not rely on their values for calculating the next state.因为this.propsthis.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.

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