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

时间:2014-07-22 21:17:56

标签: javascript reactjs

我对react.js很新,我正在通过构建砌体样式布局进行实验。

我将每个元素渲染到DOM,然后我需要遍历每个项目并根据前面的元素应用x和y位置。

初始模型如下所示:

[
  {
    "title": "The Forrest",
    "description": "some cool text",
    "imgSmallSrc": "/img/img4-small.jpg",
    "imgAlt": "Placeholder image",
    "tags": [
        "Design",
        "Mobile",
        "Responsive"
    ],
    "date": 1367154709885,
    "podStyle": {
      "width": 253
    }
  }
]

(我只展示了一个项目以保持简短。)

一旦我完成循环并获得我的x和y数据,我想将其应用于podStyle对象。我用以下数据调用setState:

[
  {
    "podStyle": {
      "x": 0,
      "y": 0,
      "height": 146,
      "width": 253
    }
  }
]

这似乎从模型中删除了所有当前数据,只留下podStyle数据。我误解了这种合并是如何运作的吗?

提前感谢您的帮助!

3 个答案:

答案 0 :(得分:67)

如果你的州是一个对象:

getInitialState: function() {
  return { x: 0, y: 0 };
}

您可以使用setState在该对象上设置单个键:

this.setState({ x: 1 }); // y still == 0

React没有智能合并你的状态;例如,这不起作用:

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)

[编辑]

如@ssorallen所述,您可以使用the immutability helpers来获得您之后的效果:

var newState = React.addons.update(this.state, {
  point: { x: {$set: 10} }
});
this.setState(newState);

有关示例,请参阅this JSFiddlehttp://jsfiddle.net/BinaryMuse/HW6w5/

答案 1 :(得分:18)

  

合并很浅,因此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

使用transform-object-rest-spread而不是Object.assign()提供已给出答案的ES7 +观点:

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(也需要来自babel预设第2阶段的transform-class-properties

{
    "presets": ["es2015", "stage-2", "react"],
    "plugins": ["transform-object-rest-spread"],
}

更新2018-04-22

正如@sheljohn指出的那样(谢谢!),引用this.state内的setState是不可靠的:

  

由于this.propsthis.state可能会异步更新,因此您不应该依赖它们的值来计算下一个状态。

     

...

     

要修复它,请使用第二种形式的setState()接受函数而不是对象。该函数将接收先前的状态作为第一个参数,并将更新应用的道具作为第二个参数

     

https://reactjs.org/docs/state-and-lifecycle.html#state-updates-may-be-asynchronous

答案 2 :(得分:4)

类似的东西:

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);

如果它是递归/深度而不是硬编码树会更好,但我会把它留给读者:)