Правило ли ReactJS повторного рендеринга справедливо: если состояние компонента изменяется, то все поддерево перерисовывается? - PullRequest
1 голос
/ 18 февраля 2020

Прежде всего, под «повторным рендерингом» здесь подразумевается либо

  1. , вызывается метод render() любого компонента класса, ИЛИ
  2. функция вызывается компонент функции.

Давайте назовем элемент в реальном DOM, изменив «refre sh», чтобы отличить guish его от «re-render».

Является ли правило «повторного рендеринга» простым, как:

Когда любое состояние компонента изменяется, то компонент и все поддерево, находящееся внизу этого компонента, повторно визуализируется

и все? Например:

function A() {
  console.log("Component A re-render");

  return <div>Component A says Hello World</div>;
}

function App() {
  const [counter, setCounter] = React.useState(0);

  console.log("Component App re-render");

  function increaseCount() {
    setCounter(c => c + 1);
  }

  return (
    <div>
      {counter}
      <button onClick={increaseCount} >Increment</button>
      <A />
    </div>
  )
}

ReactDOM.render(<App />, document.querySelector("#root"));
<script src="https://unpkg.com/react@16.12.0/umd/react.development.js" crossorigin></script>
<script src="https://unpkg.com/react-dom@16.12.0/umd/react-dom.development.js" crossorigin></script>


<div id="root"></div>

Компонент А очень прост: он даже не берет никаких реквизитов и просто выводит текст c, но он все равно вызывается каждый раз ( глядя на вывод console.log()).

Но даже если он «перерисован», фактический элемент DOM не «обновляется», как видно из элемента проверки Google Chrome, что Элемент DOM не мигает для компонента A, а мигает только для номера счетчика.

Так вот как это работает?

  1. Всякий раз, когда изменяется любое состояние компонента, это Компонент и все поддерево будут «перерисованы».
  2. Но ReactJS будет «согласовывать» содержимое «Виртуального DOM», созданного с использованием этих JSX, с содержимым фактического DOM, и если содержимое отличается, "refre sh фактического DOM".

Но, сказав это, кажется, что ReactJS на самом деле не согласуется с фактическим DOM, но согласовывается, вероятно, с «предыдущий виртуальный DOM». Почему? Потому что, если я использую setTimeout(), чтобы через 3 секунды изменить фактическое DOM компонента A на другое содержимое, и нажму кнопку, ReactJS не изменит содержимое компонента A обратно на «Hello World». Пример:

function A() {
  console.log("Component A re-render");

  return <div id="foo">Component A says Hello World</div>;
}

function App() {
  const [counter, setCounter] = React.useState(0);

  console.log("Component App re-render");

  function increaseCount() {
    setCounter(c => c + 1);
  }

  return (
    <div>
      {counter}
      <button onClick={increaseCount} >Increment</button>
      <A />
    </div>
  )
}

ReactDOM.render(<App />, document.querySelector("#root"));

setTimeout(function() {
  document.querySelector("#foo").innerText = "hi"
}, 3000);
<script src="https://unpkg.com/react@16.12.0/umd/react.development.js" crossorigin></script>
<script src="https://unpkg.com/react-dom@16.12.0/umd/react-dom.development.js" crossorigin></script>


<div id="root"></div>

Ответы [ 3 ]

1 голос
/ 18 февраля 2020

Это ответ на часть WHY вашего вопроса -

Как объясняется в этой ссылке - https://gist.github.com/paulirish/5d52fb081b3570c81e3a, многие вещи могут вызвать перезапуск DOM. Не только установка, но и доступ к свойствам элемента DOM может вызвать перекомпоновку DOM, что является очень дорогостоящим процессом.

Итак, если React начнет сравнивать с фактическим DOM, то он снизит производительность рендеринга, а не улучшит его. Вот почему «Resact» сравнивает изменения с предыдущей копией и, при необходимости, обновляет изменения в Actual DOM.

1 голос
/ 18 февраля 2020

После рендеринга реакция получает json того, как должен выглядеть вид, вычисляет изменения и затем изменяет фактическую dom. Таким образом, даже при повторном воспроизведении A вывод json будет таким же, как у виртуальной dom, и, следовательно, реакция не касается dom

0 голосов
/ 18 февраля 2020

После прочтения React docs по согласованию кажется, что упрощенный способ думать об этом:

  1. Всякий раз, когда реквизиты предоставляются компоненту COMPO1 или состоянию этого компонента изменяется, затем вызываются все render () компонентов класса и компонентов функции в COMPO1, чтобы сформировать виртуальное дерево DOM, и все поддерево сравнивается с предыдущим поддеревом - не с фактическим DOM, а с с предыдущим виртуальным поддеревом DOM
  2. Сравнивается, чтобы увидеть, отличаются ли узлы, и делают ли это рекурсивно для всех дочерних элементов. refre sh содержимого к фактическому DOM - это означает, что если у узла A есть дочерние элементы B и C, а B остался прежним, в то время как узел C стал другим, то только C вызовет эту часть фактического ДОМ должен быть обновлен. (конечно, если узел C имеет узел D, а E и D остались прежними, а E стал другим, то только E обновляется до фактического DOM).
...