代码之家  ›  专栏  ›  技术社区  ›  Rodolphe

组件已更新,但没有外观更改

  •  3
  • Rodolphe  · 技术社区  · 6 年前

    我是一个很新的反应者,我把我的头发拉到这个上面:

    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
    

    这对我来说很好,但不知何故, a b 仍然显示而不是 c d …… 我错过了什么?

    2 回复  |  直到 6 年前
        1
  •  3
  •   rorschach    6 年前

    因为你有一系列 Child 然后,元素的反应就无法区分它们是何时被新的更新/替换的。

    添加唯一的 key 对每个 孩子 它会起作用,例如

    <Child key='a' title='a'/> ,
    <Child key='b' title='b'/> ,
    等。

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

    不应在状态更改时创建整个新组件,而应只存储它们的值。( title 在这种情况下),然后 render() 方法处理它。

    下面是伪伪代码,因为我只添加了相关部分来演示它的工作方式。

    constructor() {
      this.state = {
        children: ['a', 'b']
      }
    }
    
    onClick() {
      this.setState({
        children: ['c', 'd']
      });
    }
    
    render() {
      return (
        <>
          {this.state.children.map(title => <Child key={title} title={title}/>)}
        </>
      );
    }
    
        2
  •  3
  •   Just code    6 年前

    不应在子组件中使用状态。您没有任何子属性的依赖关系,只要使用父组件的属性,它就可以正常工作。

    变化:

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

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

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

    Demo