Реакция: вызов функции после render () и перед дочерним конструктором () - PullRequest
0 голосов
/ 16 января 2019

У меня есть компонент с именем Parent , внутри которого есть еще один компонент с именем Child :

<Parent>
  <Child/>
</Parent>

Таким образом, жизненный цикл выглядит следующим образом:

  1. Родительский конструктор
  2. Родительский рендер ()
  3. Дочерний конструктор
  4. Дочерний рендер ()
  5. Дочерний монтируется
  6. Родитель установлен

Можно ли как-нибудь выполнить дополнительную инициализацию Родителя после шага 2 и до шага 3?

ОБНОВЛЕНИЕ:

class ThirdPartyLib {
  init(elementId) {
    console.log(`initializing element: ${elementId}`);
    // element with #id: elementId should exist!
    // document.getElementById(elementId).style.color = "red";
  }
}

class Parent extends React.Component {
    constructor(props) {
        super(props);
        console.log("Parent's constructor");
    }

    render() {
        console.log("rendering Parent");
        new ThirdPartyLib().init("parent");
        return (
            <div id="parent">Parent: {this.props.name}
                <Child name="Sara"/>
            </div>
        );
    }

    componentDidMount() {
        console.log("Parent is mounted");
    }
}

class Child extends React.Component {
    constructor(props) {
        super(props);
        console.log(`Child ${this.props.name} constructor`);
    }

    render() {
        console.log(`rendering Child: ${this.props.name}`);
        return <div>Child: {this.props.name}</div>
    }

    componentDidMount() {
        console.log(`Child ${this.props.name} is mounted`);
    }
}

ReactDOM.render(<Parent name="Bob"/>, document.getElementById("app"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>


<div id="app"></div>

Здесь я сделал несколько упрощений - я не просто изменяю цвет элемента, я мог бы сделать это методом componentDidMount().Скорее, специфика ThirdPartyLib определяет последовательность инициализации.Я должен инициализировать Parent сразу после того, как он появится в DOM, перед созданием любого дочернего элемента.

Если быть более точным, Parent и Child совместно используют один и тот же экземпляр класса ThirdPartyLib.Я не могу поместить логику инициализации в функцию render() Родителя, так как элемент еще не находится в DOM.Аналогично, я не могу инициализировать Parent перед Child, как это предлагается в комментариях через componentDidMount(), поскольку Child componentDidMount() выполняется до Parent.

1 Ответ

0 голосов
/ 16 января 2019

Один из способов подойти к этому - отложить рендеринг потомка до момента монтирования родителя. Шаги будут выглядеть следующим образом:

  • исходный родительский рендер не рендерит Child (например, подавить использование флага в родительском состоянии)
  • Parent componentDidMount выполняет стороннюю инициализацию и изменяет флаг в родительском состоянии, вызывая повторный рендеринг родительского
  • При повторном рендеринге Parent теперь рендерит Child, и Parent может передавать сторонней информации инициализации Child через пропеллер

Полученный код будет выглядеть примерно так:

import React from "react";
import ReactDOM from "react-dom";

class ThirdPartyLib {
  init(elementId) {
    console.log(`initializing element: ${elementId}`);
    this.element = document.getElementById(elementId);
    this.element.style.color = "red";
  }
}

class Parent extends React.Component {
  constructor(props) {
    super(props);
    this.state = { initialized: false };
    console.log("Parent's constructor");
  }

  render() {
    console.log("rendering Parent");
    return (
      <div id="parent">
        Parent: {this.props.name}
        {this.state.initialized && (
          <Child name="Sara" thirdPartyLib={this.state.thirdPartyLib} />
        )}
      </div>
    );
  }

  componentDidMount() {
    console.log("Parent is mounted");
    const thirdPartyLib = new ThirdPartyLib();
    thirdPartyLib.init("parent");
    this.setState({ initialized: true, thirdPartyLib });
  }
}

class Child extends React.Component {
  constructor(props) {
    super(props);
    console.log(`Child ${this.props.name} constructor`);
    console.log(
      `Child knows stuff from thirdPartyLib: ${
        this.props.thirdPartyLib.element.id
      }`
    );
  }

  render() {
    console.log(`rendering Child: ${this.props.name}`);
    return (
      <div>
        Child: {this.props.name}
        <br />
        ThirdPartyLib element id:
        {this.props.thirdPartyLib.element.id}
      </div>
    );
  }

  componentDidMount() {
    console.log(`Child ${this.props.name} is mounted`);
  }
}

const rootElement = document.getElementById("root");
ReactDOM.render(<Parent name="Bob" />, rootElement);

Edit 82q69v3469

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...