предотвратить размонтирование компонента при отображении в разных частях DOM - PullRequest
0 голосов
/ 17 марта 2020

Макет моего приложения меняется в зависимости от выбора, сделанного пользователем, поэтому один и тот же компонент зависает под разными узлами в DOM. К сожалению, React размонтирует и перемонтирует компонент. В результате мой компонент теряет состояние, накопленное. Я попытался добавить свойство key, чтобы передать информацию, что это тот же экземпляр, но я получил те же результаты. Ниже, очевидно, SSCCE. Каждый раз, когда пользователь нажимает кнопку, компонент A отключается и монтируется:

class A extends React.Component {
  componentWillUnmount = () => {
    console.log('map::componentWillUnmount()');
  }

  componentDidMount = () => {
    console.log('map::componentDidMount()');
  }
  render() {
    return (
      <div>
        this is component A
      </div>
    );

  }
}


class App extends React.Component {

  constructor(props) {
    super(props);
    this.state={i:0};
  }

  increment = () => {
    this.setState({i: this.state.i+1});
  }


  render() {
    console.log('app::render');
    if (this.state.i % 2 === 0)
      return (
        <>
        <div>
          <div>
            <A key={42}/>
          </div>
        </div>
        <button onClick={this.increment}>re-render</button>
        </>
      );
    else return (
      <>
      <div>
        <A key={42}/>
      </div>
      <button onClick={this.increment}>re-render</button>
      </>
    )
  }
}

Просто чтобы прояснить, мой код не пытается ничего достичь, кроме как воспроизвести проблему, как я сказал, это SSCCE. Конечно, есть приложения, в которых пользователь может изменить макет из меню «предпочтений», чтобы компонент оказывался в другом месте в DOM в зависимости от предпочтений пользователя. Я не могу представить себе приемлемым потерять государство в такой ситуации. Как правильно обращаться с подобными ситуациями?

1 Ответ

0 голосов
/ 17 марта 2020

Это связано с тем, что условный рендеринг возвращает две разные древовидные структуры, в которых путь к A отличается.

  • React.Fragment> div> div> A
  • React.Fragment> div> A

Представьте, что если мы имитируем React с помощью простого JS, чтобы выполнить монтирование и размонтирование вручную, нам потребуется:

  1. Сохранить <A/> как переменную
  2. Удалить внутренняя <div/> (<A/> также будет автоматически удалена)
  3. Затем добавьте ранее сохраненную <A/> во внешнюю <div/> (что на самом деле также не является хорошим подходом, потому что это предполагает <A/> никогда не потребуется обновлять себя после монтирования, даже если реквизиты меняются)

Пока есть удаление и добавление, это вполне равносильно тому, что компонент React был размонтирован и затем снова смонтирован.

Код немного расплывчатый, и я не могу сказать, чего он пытается достичь, имея 2 <div/> s в первом условии и только 1 <div/> во втором. Но, возможно, вы можете использовать троичные операторы для условного рендеринга именно того, что вам нужно, и оставить <A/> в покое (и может быть немного CSS, чтобы внутренний <div/> выглядел так, как будто он вложен в другой <div/>). Таким образом, <A/> не будет размонтирован, когда <App/> изменит состояние.

return (
  <>
    <div>
      <A />
      {condition ? // where `condition` is a boolean
        <div style={{
          position: 'absolute'
          // and may be other styles to achieve the visual trickery
        }}>
          {/* your content here */}
        </div>
        :
        null
      }
    </div>
    <button onClick={this.increment}>re-render</button>
  </>
)

Кстати, говорят, 42 - это ответ на все вопросы, но я думаю, что не для этого случая. Установка ключа на 42 не поможет. ?

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