【问题标题】:Member variables in react class are "shared" by reference反应类中的成员变量通过引用“共享”
【发布时间】:2015-04-17 10:55:23
【问题描述】:

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

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

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

【问题讨论】:

  • "寻求调试帮助的问题(“为什么这段代码不起作用?”)必须包括所需的行为、特定的问题或错误以及重现它所需的最短代码在问题本身。没有明确问题陈述的问题对其他读者没有用处。请参阅:如何创建Minimal, Complete, and Verifiable example。"
  • 我建议您在 SO 上发布代码的(相关)部分,并且您可能还想查看 JavaScript 范围内的 JavaScript 文档:smashingmagazine.com/2009/08/01/…
  • @TedNyberg:从描述来看,这与范围无关。这很可能与原型上的原语和对象引用之间的差异有关。
  • @T.J.Crowder 这听起来很对。可以向 OP 推荐以下链接:stackoverflow.com/questions/518000/…

标签: javascript reactjs


【解决方案1】:

你应该做的是在你的组件上设置状态,而不是在你的 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 中。

为此使用 props 和 state 的好处是,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);

【讨论】:

  • 感谢您的快速回复安德斯!在“componentWillMount”函数中为“this”分配属性对我来说听起来很“骇人听闻”。但同样地,在我的用例中,变量也不像是一个道具或组件的状态。在我的情况下,我有一个处于状态的消息数组,并希望创建一个消息索引以更快地访问它们或更快地检查它们的存在(messagesIndex)。我再举一个例子:jsbin.com/guwipeyubu/1/edit?html,js,console,output
  • 是的,它感觉很hackish的原因是它不是很地道,也不是你“应该”做的事情。我无法真正掌握您的示例应该做什么,但作为一般经验法则;如果数据是应该由组件呈现的东西,它肯定应该是一个道具或状态的一部分。如果它不是应该被渲染的东西(即在 render 方法中使用),它可能不属于组件。
  • 如果它令人满意地解决了您的问题,请接受此答案。顺便说一句,这是一个很好的答案。
  • 安德斯的回答应该被接受。帖子中提出的问题已得到解答。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-04-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多