web-dev-qa-db-fra.com

ReactJS - Détruisez l'ancienne instance de composant et créez une nouvelle

J'ai une question qui peut prêter à confusion car elle ne correspond pas au comportement standard de la façon dont réagissent et le dom virtuel fonctionne, mais je voudrais quand même connaître la réponse.

Imaginez que j'ai un simple composant de réaction qui s'appelle "Container". Le conteneur-composant a un "div" à l'intérieur de la méthode de rendu qui contient un autre composant appelé "ChildContainer". Le "div" qui entoure le "ChildContainer" a l'ID "wrappingDiv".

Exemple:

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

Comment puis-je détruire l'instance de composant "ChildContainer" et en créer une complètement nouvelle. Ce qui signifie que le "ComponentWillUnmount" de l'ancienne instance est appelé et le "ComponentDidMount" du nouveau composant est appelé.

Je ne veux pas que l'ancien composant soit mis à jour en changeant l'état ou les accessoires.

J'ai besoin de ce comportement, car une bibliothèque externe de notre société partenaire a obtenu une bibliothèque qui modifie les éléments dom et dans React je vais obtenir une exception "Node not found" lorsque je mets à jour le composant.

6
Kevin H.

Si vous donnez au composant un key et modifiez ce key lors du nouveau rendu, l'ancienne instance du composant sera démontée et la nouvelle sera montée:

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

L'enfant aura un nouveau key à chaque fois, donc React supposera qu'il fait partie d'une liste et jettera l'ancien, créant le nouveau. Tout changement d'état dans votre Le composant qui provoque son nouveau rendu forcera ce comportement de démontage et de recréation sur l'enfant.

Exemple en direct:

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>

Cela dit, il pourrait bien y avoir une meilleure réponse à votre problème sous-jacent avec le plugin. Mais ce qui précède répond à la question réellement posée ... :-)

6
T.J. Crowder