Как React.useState снова запускает содержащую функцию? - PullRequest
0 голосов
/ 08 марта 2020

Скажем, у нас есть простой функциональный компонент:

export function MyComp(){

   const [state, setState] = React.useState({foo:1});

   setTimeout(() => setState({foo:2}, 45);

   return (
    <div> {state.foo} </div>
   )

}

Как бы он рендерился, если бы setState волшебным образом не вызвал MyComp() снова? И если он снова волшебным образом вызывает MyComp(), как это работает?

Ответы [ 2 ]

1 голос
/ 08 марта 2020

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

Во-первых, React должен иметь список всех компонентов в вашем приложении, мы упростим его списком, но на самом деле это дерево:

const nodes = <>
  <h1>My Counter</h1>
  <Counter />
  <div>
</>

Так что на этом этапе, если бы ваше приложение было плоским, DummyReactDOM.render(nodes) создаст список этих node ":

nodes = [ h1, Counter, div ]

Ситуация становится сложной, когда вызывается useState, и React будет сохранять какое-то состояние (запомненное состояние), например, узел Counter может выглядеть так:

function Counter() {
  [ counter, setCounter ] = useState(0);
}

Это добавит состояние к узлу:

node Counter = {
  state : {
    counter: 0
    next  : null
  }
}

Теперь, что происходит, когда мы нажимаем на компонент и вызываем setCounter(counter + 1)? A next состояние добавлено в очередь:

node Counter = {
  state : {
    counter : 0,
    next    : {
      state : {
        counter : 1, // <-- setCounter(counter + 1 happens)
        next    : null,
      }
    }
  }
}

// firstState.next -> secondState.next -> null

Теперь планировщик - это главный ум узнать, какие компоненты необходимо перерисовать. Вот очень нереалистично c но простой для восприятия способ увидеть это:

while (true) {

  // sleepForABit();

  if (currentNode.state.next !== null && currentNode.state !== currentNode.state.next) {
    currentNode.state = currentNode.state.next;
    currentNode.component.render(); // or functionalComponent() call
  }

  currentNode = currentNode.next
}

Это простой случай если бы это был список узлов, но очевидно, что поскольку узел должен быть перерисован, React проверит его дочерние элементы. Важно отметить, что повторное рендеринг не так уж и дорого, дорогая часть - воссоздание DOM-узлов (и, в меньшей степени, их обновление), поэтому проверка дочерних узлов в большинстве случаев весьма производительна.

Надеюсь, это поможет!

В случае, если вам интересно, почему мы можем сделать setCounter(counter + 1), не имея counter = 0 всегда, React гарантирует, что узлы будут перерисованы при определенных событиях (onClick как единое целое из многих).

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

В вашем коде setState волшебным образом не вызывает ваш компонент, но вызывает повторную визуализацию. Следовательно, выполнение setState(someValue) в вашем случае является причиной повторного рендеринга MyComp. Вы можете прочитать больше об этом и зацепках в документации React: https://reactjs.org/docs/hooks-state.html#recap

Надеюсь, что это ответ на ваш вопрос!

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