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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/29697268/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-23 03:49:02  来源:igfitidea点击:

Member variables in react class are "shared" by reference

javascriptreactjs

提问by delijah

When i create several instances of a react class (by using React.createElement on the same class), some member variables are shared between the instances (arrays and objects are shared, strings and booleans etc. not).

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

For me this feels horrible and scary and wrong. Is this a bug or is there another way to do what i want to do?

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

Please have a look: http://jsbin.com/kanayiguxu/1/edit?html,js,console,output

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

回答by Anders Ekdahl

What you should be doing is setting state on your component, instead of having state as arbitrary properties on your React component.

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

So instead of doing this:

所以不要这样做:

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

You should be doing this:

你应该这样做:

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

The reason being that all of a components state and data should reside in this.stateand this.propswhich is controlled and handled by React.

原因是,所有一组件状态和数据的应驻留在this.statethis.props被控制,并通过阵营处理。

The benefit you get from using props and state for this, is that React will know when those change, and from that it can tell when it's time to re-render your component. If you store state as arbitrary properties or globals, React won't know when those change, and cannot re-render for you.

使用 props 和 state 的好处是,React 会知道它们何时发生变化,并且从中可以判断何时需要重新渲染组件。如果您将状态存储为任意属性或全局变量,React 将不知道它们何时发生变化,也无法为您重新渲染。

The reason for the behaviour you're seeing is that every instance of the component uses the object you give to React.createClass()as its prototype. So all instances of the component has a myArrayproperty, but that is on the prototype chain, and thus shared by all instances.

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

If you truly want something like this and you want to avoid this.state, you should use something like componentWillMountand inside that method, assign properties to this. This will make sure that such data is only on that particular instance, and not on the prototype chain.

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

EDIT

编辑

To even further clearify, it can be good to know that the object passed to React.createClass()isn't the actual object on the prototype. What React does is that it iterates over all properties on that object, and copies them onto the prototype of the React element object. This can be illustrated by this example:

为了进一步澄清,最好知道传递给的对象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);