Как React Hooks использует Callback, «замораживая» замыкание? - PullRequest
0 голосов
/ 07 февраля 2019

Я хотел бы знать, что React «замораживает» замыкание при использовании хука useCallback (и вместе с другими), обновляя переменные, используемые внутри хука, если вы не передадите их в параметр inputs.

Я знаю, что слово "заморозить" очень странное, поэтому я создал REPL.it, который объясняет, что я имею в виду: https://repl.it/repls/RudeMintcreamShoutcast. Пожалуйста, откройте веб-консоль и начните нажимать кнопку count.

Почему значение снаружи / внутри для одной и той же переменной отличается, если они находятся под одним и тем же замыканием и ссылаются на одно и то же?Я не знаком с базой данных React, и мне здесь тоже может не хватать чего-то большого, но я пытался подумать, как это может работать в течение нескольких минут, но не могу понять, что именно происходит под капотом.

1 Ответ

0 голосов
/ 07 февраля 2019

При первом рендеринге компонента хук useCallback примет функцию, переданную в качестве аргумента, и сохранит ее за кулисами.Когда вы вызываете обратный вызов, он вызовет вашу функцию.Пока все хорошо.

Во второй раз, когда компонент визуализируется, хук useCallback проверит переданные вами зависимости. Если они не изменились, передаваемая вами функция полностьюпроигнорировано !Когда вы вызываете обратный вызов, он вызывает функцию, которую вы передали при первом рендеринге, которая все еще ссылается на те же значения с того момента времени.Это не имеет ничего общего со значениями, которые вы передали в качестве зависимостей - это просто обычные JavaScript-замыкания!

При изменении зависимостей хук useCallback примет переданную вами функцию и заменит сохраненную функцию,Когда вы вызываете функцию обратного вызова, она вызывает новую версию функции.

Другими словами, нет «замороженных» / условно обновленных переменных - это просто сохранение функции, а затемповторное использование, ничего более причудливого, чем это:)

РЕДАКТИРОВАТЬ: Вот пример, который демонстрирует, что происходит в чистом JavaScript:

// React has some component-local storage that it tracks behind the scenes.
// useState and useCallback both hook into this.
//
// Imagine there's a 'storage' variable for every instance of your
// component.
const storage = {};

function useState(init) {
  if (storage.data === undefined) {
    storage.data = init;
  }
  
  return [storage.data, (value) => storage.data = value];
}

function useCallback(fn) {
  // The real version would check dependencies here, but since our callback
  // should only update on the first render, this will suffice.
  if (storage.callback === undefined) {
    storage.callback = fn;
  }

  return storage.callback;
}

function MyComponent() {
  const [data, setData] = useState(0);
  const callback = useCallback(() => data);

  // Rather than outputting DOM, we'll just log.
  console.log("data:", data);
  console.log("callback:", callback());

  return {
    increase: () => setData(data + 1)
  }
}

let instance = MyComponent(); // Let's 'render' our component...

instance.increase(); // This would trigger a re-render, so we call our component again...
instance = MyComponent();

instance.increase(); // and again...
instance = MyComponent();
...