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

Dan*_*anV 53 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
    }
  }
]
Run Code Online (Sandbox Code Playgroud)

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

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

[
  {
    "podStyle": {
      "x": 0,
      "y": 0,
      "height": 146,
      "width": 253
    }
  }
]
Run Code Online (Sandbox Code Playgroud)

这似乎从模型中删除了所有当前数据,只留下podStyle数据.我误解了这次合并的效果吗?

在此先感谢您的帮助!

Mic*_*ley 71

如果您的州是一个对象:

getInitialState: function() {
  return { x: 0, y: 0 };
}
Run Code Online (Sandbox Code Playgroud)

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

this.setState({ x: 1 }); // y still == 0
Run Code Online (Sandbox Code Playgroud)

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)
Run Code Online (Sandbox Code Playgroud)

[编辑]

正如@ssorallen所提到的,你可以使用不变性助手来获得你想要的效果:

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

请参阅此JSFiddle以获取示例:http://jsfiddle.net/BinaryMuse/HW6w5/


pti*_*tim 19

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

为已经给出的答案提供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
    }
}
Run Code Online (Sandbox Code Playgroud)

.babelrc(也需要来自babel预设第2阶段的transform-class-properties)

{
    "presets": ["es2015", "stage-2", "react"],
    "plugins": ["transform-object-rest-spread"],
}
Run Code Online (Sandbox Code Playgroud)

更新时间2018-04-22

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

因为this.props并且this.state可以异步更新,所以不应该依赖它们的值来计算下一个状态.

...

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

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

  • 我是新来的反应者,但这似乎是错误的。`handleChange` [应该调用](https://reactjs.org/docs/state-and-lifecycle.html#state-updates-may-be-asynchronous)`this.setState((prevState,props)=>({ ... //使用prevState.point}))`代替。 (2认同)