React未从数组内的对象更新属性

React not updating property from an object inside an array

本文关键字:对象 更新 属性 数组 React      更新时间:2023-09-26

我想做的是动态添加新元素,并在未来的某个时候更改它们的样式。为此,我尝试创建一个对象,该对象将进入状态,并包含两个设置了数组值的属性:一个是保存元素本身的数组,另一个保存与之相关的样式。

但出于某种原因,即使我尝试创建一个包含这两个属性的对象的副本(有人说,将状态视为stackoverflow上的不可变状态)并更新它,然后将状态设置为新对象,它似乎仍然没有更新。

我也尝试过这个解决方案,但它仍然会出现同样的问题。

var React = require('react');
var ReactDOM = require('react-dom');
var update = require('react-addons-update');

var Book = React.createClass({
    getInitialState() {
        return {
            pages: {
                pageElements: [], pageStyle: []
            }
        };
    },
    changeStyle: function (e) {
        this.setState(update(this.state.pages.pageStyle[0],
            {name: {$set: {position: 'absolute', transform: 'translate(50px,100px)'} }}));
    },
    componentDidMount: function () {
        let pagesCopy = {
            pageElements: this.state.pages.pageElements, pageStyle: []
        };
        pagesCopy.pageStyle.push({styles: {position: 'absolute'}});
        pagesCopy.pageElements.push(
            <img
                key={0}
                onMouseDown={this.changeStyle}
                style={this.state.pages.pageStyle[0]}
                src={'/pages/0'}
                height="800px"
                width="600px"/>);
        this.setState({pages: pagesCopy});
    },
    render: function () {
        return (
            <div>
                <section style={{position: 'relative', height:800, width:1200, margin: 'auto'}}>
                    {this.state.pages.pageElements}
                </section>
            </div>
        )
    }
});
ReactDOM.render(<Book/>, document.getElementById("content"));

我认为问题在于以下几点:

style={this.state.pages.pageStyle[0]}

它直接引用对象。我认为它将这个值永久地设置为样式,因为只能有状态的副本,所以它看不到持有这两个属性的新对象上的更新值。我还研究了如何获得对数组索引的引用,以便它在每次更新状态时都会获取它,但最终,它只是使该值成为最终值并保持静态(我认为)。

注意:该代码是一个更大代码的超级简化版本,但我这里的代码是导致问题的基本代码

首先,我想指出您的代码中有一些我认为是拼写错误的地方。在componentDidMount()中,您在推入pagesCopyimg组件上设置以下道具:

style={this.state.pages.pageStyle[0]}

由于this.state.pages.pageStyle在当时是一个空数组,我相信你的意思是设置道具如下:

style={pagesCopy.pageStyle[0]}

一旦解决了这个问题,我认为你已经正确地诊断出了直接原因。也就是说,您存储在this.state.pages.pageElements[0]中的img组件包含对对象的引用(pagesCopy.pageStyle[0],后来成为this.state.pages.pageStyle[0])。当您调用changeStyles()时,您正在创建一个新对象,而不是更改旧对象。这是一个问题,因为img组件上的样式道具仍然包含对旧对象的引用,而旧对象没有更改。

如果您需要在紧急情况下进行此操作,我的建议是在changeStyles()方法中直接更改this.state.pages.pageStyle[0]中的对象,然后调用forceUpdate()。调用forceUpdate()将导致重新渲染。img组件将重新渲染,其样式道具将包含对具有新属性值的旧对象的引用。下面的代码可以做到这一点:

changeStyle: function() {
  var styles = this.state.pages.pageStyle[0];
  styles.position = 'absolute';
  styles.transform = 'translate(50px,100px)';
  this.forceUpdate();
}

现在,我要强调的是,这是非常非常糟糕的做法。直接改变状态几乎总是个坏主意。如果有充分的理由这么做的话,我还没有听说。

以下是如何在不直接改变状态的情况下做到这一点的建议。

var Book = React.createClass({
  getInitialState() {
    return {
      pageElements: [
        {
          tagName: 'img',
          props: {
            src: 'http://www.keenthemes.com/preview/metronic/theme/assets/global/plugins/jcrop/demos/demo_files/image1.jpg',
            height: '800px',
            width: '600px',
            style: {
              position: 'absolute'
            }
          }
        }
      ]
    };
  },
  changeStyle: function(e) {
    this.setState(function(previousState) {
      var newState = _.extend({}, previousState);
      newState.pageElements[0].props.style = {
        position: 'absolute',
        transform: 'translate(50px,100px)'
      };
      return newState;
    });
  },
  render: function () {
    return (
      <div>
        <section style={{ position: 'relative', height: 800, width: 1200, margin: 'auto' }}>
          {
            this.state.pageElements.map(function(pageElement, index) {
              return React.createElement(pageElement.tagName,
                _.extend(pageElement.props, {
                  key: index,
                  onMouseDown: this.changeStyle.bind(this)
                })
              );
            }.bind(this))
          }
        </section>
      </div>
    );
  }
});
React.render(<Book/>, document.getElementById('content'));