更新动态创建的组件

时间:2018-04-16 17:10:02

标签: javascript reactjs redux react-redux

情况

我有一个父组件,它呈现一些子组件。 子组件应显示从父组件传递的信息。

上下文

与多人游戏的战舰游戏:

父组件包含10x10到​​10x30按钮(子组件)的字段。如果按下按钮,则具有按钮位置的信号将被发射到api。 api决定按下的按钮是否需要改变它的颜色。

问题

通过更新父级的状态,如果动态创建子级,子组件props将不会更新。

解决方案尝试

不要动态渲染Childs:

在我的情况下不可能

使用redux

我将子视为dump / presentational Component,因为它只显示信息。在我的情况下,还有100-300个子组件。 Redux and React

使用refs

有100-300个子组件...... Don’t Overuse Refs

问题

我该怎么办?有没有反模式的解决方案?

现行守则



class Parent extends React.Component {
  constructor(props) {
    super(props);
    this.state={
      foo: 'BAR'
    }
    this.child=undefined;
  }
  
  componentWillMount(){
    this.child=<Child foo={this.state.foo}/>
  }  
  
  componentDidMount(){
    var that=this
    setTimeout(function(){ 
      that.setState({  //it is just here for demonstration
        foo: 'FOO'
      }) 
    }, 1000);
  }
  
  render() {
    return (
      <div>
       Is: {this.child}
       Not Dynamic created: <Child foo={this.state.foo}/>
       Actual: <p>{this.state.foo}</p>
      </div>
    );
  }
}

class Child extends React.Component {
  render() {
    return (
      <p>{this.props.foo}</p>
    );
  }
}

ReactDOM.render(<Parent />, document.getElementById('app'));
&#13;
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="app"></div>
&#13;
&#13;
&#13;

来自@RaghavGarg和@Clinton Blackburn的代码

&#13;
&#13;
class Parent extends React.Component {
  constructor(props) {
    super(props);
    this.state={
      foo: 'BAR'
    }
    this.child=undefined;
  }
  
  componentDidMount(){
    var that=this
    setTimeout(function(){ 
      that.setState({  //it is just here for demonstration
        foo: 'FOO'
      }) 
    }, 1000);
  }
  
  renderChild(){
    return <Child foo={this.state.foo} />
  }
  
  render() {
    const child=this.renderChild()
    return (
      <div>
       Is: {child}
       Not Dynamic created: <Child foo={this.state.foo}/>
       Actual: <p>{this.state.foo}</p>
      </div>
    );
  }
}

class Child extends React.Component {
  render() {
    return (
      <p>{this.props.foo}</p>
    );
  }
}

ReactDOM.render(<Parent />, document.getElementById('app'));
&#13;
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id='app'/>
&#13;
&#13;
&#13;

2 个答案:

答案 0 :(得分:2)

就像@Clinton所说,componentWillMount只会被调用一次。所以你基本上是在发起你的this.child变量,但只是更新状态,你还需要更新变量的值。

由于您只是制作动态组件并将其保存在类实例中(如this.child)。我建议您在componentWillUpdate中执行相同的任务。因此,无论何时状态发生变化,它都会反映在您的因变量中。但请确保不要在此生命周期方法中使用setState

  在渲染新道具之前调用

componentWillUpdate()   或正在收到国家。以此为契机   更新发生前的准备工作。

另外,请考虑使用构造函数来启动状态,而不是在setState中使用componentWillMount

  在安装发生之前调用

componentWillMount()。它是   在render()之前调用,因此同步调用setState()   此方法不会触发额外渲染。一般来说,我们   建议使用constructor()代替初始化状态。

参考:

https://reactjs.org/docs/react-component.html#unsafe_componentwillupdate https://reactjs.org/docs/react-component.html#unsafe_componentwillmount

添加上下文后更新

所以现在,我假设您将在维持每个框(子组件)状态的状态下拥有DS(可能是对象或嵌套数组)。你可以遍历它并为它们中的每一个提供唯一的key(可能像{row}-{col}),现在你只需要更新状态以反映特定孩子的变化。

注意:使用每个子项的唯一键将启用内部优化重新呈现,并且不会重新呈现子项(使用唯一键),这不会更改。请参阅以下代码以供参考。

this.state = {
  boxes: {
    1: { 
      1:{ status: true, /* more data */ },
      2:{ status: true, /* more data */ },
    },
    2: { 
      1:{ status: true, /* more data */ },
      2:{ status: true, /* more data */ },
    },
    3: { 
      1:{ status: true, /* more data */ },
      2:{ status: true, /* more data */ },
    },
    4: { 
      1:{ status: true, /* more data */ },
      2:{ status: true, /* more data */ },
    }
  }
};

// this will create a 4x2 box, now you will render using above object

// ...somewhere in your render method
{
  Object.keys(this.state.boxes).map(row => (
    <div key={`row-${row}`} className="row">
      {
        Object.keys(this.state.boxes[row]).map(column => (
          <Child 
            key={`box-${row}x${column}`} 
            data={this.state.boxes[row][column]} 
          />
        ))
      }
    </div>
  ))
}

现在,每当您将status 2x1 false框更改为box-2x1时,反应将仅使用密钥shouldComponentUpdate重新呈现该儿童。

OP comment

之后的更新 应该使用

true来决定是否要在状态更改时更新组件。它是React组件的生命周期方法。默认情况下,它返回false,但您可以根据条件返回Class Game: def __init__(): points = 0 self.hidden_password = [] self.hidden_password2 = [] self.country = "" self.used = [] self.start_time = datetime.now() self.welcome() # This should be in main function self.choice() # This should be in main function def choice(self, ...): pass def welcome(self, ...): pass def guessing_capital(self, ...): pass def checking_password(self, ...): pass 以不更新组件。这肯定有助于保持良好的表现。

参考: React: Parent component re-renders all children, even those that haven't changed on state change

答案 1 :(得分:1)

componentWillMount仅在将父组件插入DOM时调用一次。可能不是您想要创建安装后需要更改的子组件的位置。 请参阅https://reactjs.org/docs/react-component.html#the-component-lifecycle处的组件生命周期。

最简单的解决方案是在render()方法中创建子组件。更新父组件时将重新创建子组件。