react类中的成员变量通过引用“共享”

时间:2015-04-17 10:55:24

标签: javascript reactjs

当我创建一个react类的几个实例时(通过在同一个类上使用React.createElement),一些成员变量在实例之间共享(数组和对象是共享的,字符串和布尔值等等)。

对我来说,这感觉太可怕,可怕和错误。这是一个错误,还是有另一种方法可以做我想做的事情?

请看一下: http://jsbin.com/kanayiguxu/1/edit?html,js,console,output

1 个答案:

答案 0 :(得分:11)

您应该做的是在组件上设置状态,而不是在React组件上将状态作为任意属性。

所以不要这样做:

var MyComponent = React.createClass({
  myArray: [1, 2, 3],
  componentWillMount() {
    this.myArray.push(this.myArray.length + 1);
  },
  render() {
    return (
      <span>{this.myArray.length}</span>
    );
  }
});

你应该这样做:

var MyComponent = React.createClass({
  getInitialState() {
    return {
      myArray: [1, 2, 3]
    };
  },
  componentWillMount() {
    this.setState(state => {
      state.myArray.push(state.myArray.length + 1);
      return state;
    });
  },
  render() {
    return (
      <span>{this.myArray.length}</span>
    );
  }
});

原因是所有组件状态和数据都应驻留在由{React}控制和处理的this.statethis.props中。

使用道具和状态获得的好处是,React会知道这些更改的时间,并且可以告诉它什么时候重新渲染您的组件。如果您将状态存储为任意属性或全局变量,则React不会知道何时更改,并且无法为您重新渲染。

您所看到的行为的原因是组件的每个实例都使用您提供给React.createClass()的对象作为其原型。因此,组件的所有实例都具有myArray属性,但它位于原型链上,因此由所有实例共享。

如果你真的想要这样的东西而你想避免使用this.state,那么你应该使用类似componentWillMount之类的内容,并在该方法中为this指定属性。这将确保此类数据仅在该特定实例上,而不在原型链上。

<强> 修改

为了进一步澄清,最好知道传递给React.createClass()的对象不是原型上的实际对象。 React做的是迭代该对象上的所有属性,并将它们复制到React元素对象的原型上。这可以通过这个例子说明:

var obj = {
  myArray: [1, 2, 3],
  title: 'My title',
  componentWillMount() {
    this.myArray.push(this.myArray.length + 1);
  },
  render() {
    return (
      <span>{this.myArray.length}</span>
    );
  }
}

var MyComponent = React.createClass(obj);

// This doesn't change the component, since 'obj' isn't used anymore
// by React, it has already copied all properties.
obj.title = 'New title';

// This however affects the component, because the reference to the array
// was copied to the component prototype, and any changes to what the 
// reference points to will affect everyone who has access to it.
obj.myArray.push(666);