ReactJS-销毁旧的组件实例并创建新的

时间:2018-09-10 14:40:31

标签: javascript reactjs dom

我有一个可能令人困惑的问题,因为它不符合标准行为,即如何反应以及虚拟dom的工作原理,但我还是想知道答案。

想象一下,我有一个简单的反应组件,称为“容器”。 容器组件在渲染方法内部有一个“ div”,其中包含另一个名为“ ChildContainer”的组件。包围“ ChildContainer”的“ div”的ID为“ wrappingDiv”。

示例:

render() {
  <Container>
    <div id="wrappingDiv">
      <ChildContainer/>
    </div>
  </Container
}

我如何销毁“ ChildContainer”组件实例并创建一个全新的实例。这意味着将调用旧实例的“ ComponentWillUnmount”,并调用新组件的“ ComponentDidMount”。

我不希望通过更改状态或道具来更新旧组件。

我需要这种行为,因为我们合作伙伴公司的外部库获得了一个库,该库可以更改dom项,并且在React中,当我更新组件时,我会收到“找不到节点”异常。

2 个答案:

答案 0 :(得分:9)

如果给组件一个key,并在重新渲染时更改该key,则旧的组件实例将被卸载,而新的实例将被装载:

render() {
  ++this.childKey;
  return <Container>
    <div id="wrappingDiv">
      <ChildContainer key={this.childKey}/>
    </div>
  </Container>;
}

孩子每次都会有一个新的key,因此React将假定它是列表的一部分,并丢弃旧的列表,从而创建新的列表。您的组件中任何导致其重新呈现的状态更改都将迫使该卸载和重新创建的行为作用于子代。

实时示例:

class Container extends React.Component {
  render() {
    return <div>{this.props.children}</div>;
  }
}

class ChildContainer extends React.Component {
  render() {
    return <div>The child container</div>;
  }
  componentDidMount() {
    console.log("componentDidMount");
  }
  componentWillUnmount() {
    console.log("componentWillUnmount");
  }
}

class Example extends React.Component {
  constructor(...args) {
    super(...args);
    this.childKey = 0;
    this.state = {
      something: true
    };
  }

  componentDidMount() {
    let timer = setInterval(() => {
      this.setState(({something}) => ({something: !something}));
    }, 1000);
    setTimeout(() => {
      clearInterval(timer);
      timer = 0;
    }, 10000);
  }
  
  render() {
    ++this.childKey;
    return <Container>
      {this.state.something}
      <div id="wrappingDiv">
        <ChildContainer key={this.childKey}/>
      </div>
    </Container>;
  }
}

ReactDOM.render(
  <Example />,
  document.getElementById("root")
);
<div id="root"></div>

<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.4.2/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.4.2/umd/react-dom.production.min.js"></script>


话虽如此,对于您的插件潜在问题,可能会有更好的答案。但以上内容解决了实际提出的问题...:-)

答案 1 :(得分:1)

使用钩子,首先创建一个状态变量来保存密钥:

const [childKey, setChildKey] = useState(1);

然后使用 useEffect 钩子更新渲染时的键:

useEffect(() => {
   setChildKey(prev => prev + 1);
});

注意:您可能希望 useEffect 中的数组参数中的某些内容仅在特定状态更改时更新键