【问题标题】:ReactJS - Destroy old Component-Instance and create newReactJS - 销毁旧的组件实例并创建新的
【发布时间】:2019-02-15 00:48:44
【问题描述】:

我有一个可能令人困惑的问题,因为它不符合反应和虚拟 dom 工作方式的标准行为,但我还是想知道答案。

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

例子:

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

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

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

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

【问题讨论】:

    标签: javascript reactjs dom


    【解决方案1】:

    如果你给组件一个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>

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

    【讨论】:

    • 救命稻草,683k rep 意味着什么 :)
    • 嘿克劳德,我应该怎么做?
    • 绝对是救命稻草
    • 该死的,这一定是我刚刚学到的关于 react 的最好的事情之一,谢谢!
    【解决方案2】:

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

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

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

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

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

    【讨论】:

    • 完美。正是我想要的
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-10-04
    • 2013-04-27
    • 1970-01-01
    • 2020-01-26
    • 1970-01-01
    • 1970-01-01
    • 2018-05-08
    相关资源
    最近更新 更多