组件已更新,但外观没有变化

时间:2018-12-12 09:10:03

标签: javascript html reactjs

我对React还是很陌生,我正在把头发拉出来:

HTML

<div id="root"></div>

JS

class Child extends React.Component {
  constructor(props) {
    super(props);
    this.state = { title: props.title };
  }

  render() {
    return ()<div>{this.state.title}</div>);
  }
}

class TestApp extends React.Component {
  constructor(props) {
    super(props);
    this.state = { 
      children: [
        <Child title='a' />,
        <Child title='b' />
      ]};
  }

  componentDidUpdate(prevProps, prevState) {
    console.log('[componentDidUpdate]');
    console.log('prevChildren: ' + prevState.children.map(c => c.props.title).join(', '));
    console.log('children: ' + this.state.children.map(c => c.props.title).join(', '));
  }

  handleOnClick = () => {
    console.log('[handleOnClick]');

    this.setState((prevState) => {
      return {
        children: [
          <Child title='c' />,
          <Child title='d' />
        ]
      };
    });
  };

  render() {
    console.log('[render]');

    return (
      <div>
        <div>TEST</div>
        {this.state.children}
        <button onClick={this.handleOnClick}>CHANGE</button>
      </div>
      )
  }
}

ReactDOM.render(<TestApp />, document.getElementById('root'));

CodePen:https://codepen.io/robloche/pen/xmGMBy

当我单击按钮时,控制台中发生的事情是:

[handleOnClick]
[render]
[componentDidUpdate]
prevChildren: a, b
children: c, d

对我来说看起来不错,但是仍然以某种方式显示ab而不是cd ... 我想念什么?

2 个答案:

答案 0 :(得分:3)

您不应在子组件中使用状态。您对子道具没有任何依赖性,只需使用父组件的道具就可以了。

更改:

return (<div>{this.state.title}</div>);

return (<div>{this.props.title}</div>);

您现在面临的问题是父代已更改为c,d,并且也已作为子代传递,但是由于react没有任何键更新或状态更新,因此它不会重新呈现该组件。最好的方法是使用从父级传递来的道具并使用它们。

Demo

答案 1 :(得分:3)

由于您有一个Child元素数组,因此React无法区分它们何时实际被更新/替换为新元素。

为每个key添加唯一的Child,例如,

<Child key='a' title='a'/>
<Child key='b' title='b'/>

NB!当处理组件数组时,key属性是强制性的,虽然在这种情况下也有帮助,但是您当前的方法不是很理想。

您应该只存储它们的值(在这种情况下为title,然后使用render()方法来处理状态,而不是在状态更改时创建全新的Components。

以下是伪伪代码,因为我只添加了相关部分以显示其工作原理。

constructor() {
  this.state = {
    children: ['a', 'b']
  }
}

onClick() {
  this.setState({
    children: ['c', 'd']
  });
}

render() {
  return (
    <>
      {this.state.children.map(title => <Child key={title} title={title}/>)}
    </>
  );
}