Могу ли я рассчитывать на порядок использования в компоненте? - PullRequest
3 голосов
/ 09 апреля 2020

Рассмотрим следующий шаблон:

const Comp = ({ handler })=> {
  // handler is some callback of the form ( ) => void
  useSomeHook(handler);
  //...
}

function useSomeHook(cb) {
  const ref = useRef()

  useEffect(() => {
    ref.current = cb; // update ref before second useEffect
  })

  useEffect(() => {
    // use the current (most recent) ref value
    const iv = setInterval(() => { ref.current() }, 3000) 
    return () => { clearInterval(iv) };
  }, []) // run only after first render
}

Вопрос: Могу ли я рассчитывать на тот факт, что первый useEffect всегда всегда выполнен до секунды useEffect, значит, ref уже обновлен?

Справочная информация. Мое намерение состоит в том, чтобы не запоминать переданный обратный вызов в Comp (useCallback) и устанавливать cb как dep , Мне особенно интересно, если этот изменчивый шаблон ref действителен в мире React - выше, это просто надуманный пример.

Я думал, что ответом будет четкое «Да!», После прочитав твит от Дана Абрамова . Тем не менее, следующая проблема гласит:

Мы не даем гарантий относительно порядка братьев и сестер, будь то внутри компонента или между братьями и сестрами. Это потому, что сильные гарантии мешают рефакторингу. Внутри компонента вы должны иметь возможность переупорядочивать крючки, особенно пользовательские .

Правильно ли я истолковал приведенное выше утверждение или ссылки несколько противоречивы? Ценю любые разъяснения.

PS: Мне известно о связанных постах . Этот вопрос больше касается общего порядка, официальных документов и связанных с ними противоречивых (?) Заявлений.

Спасибо!

1 Ответ

1 голос
/ 09 апреля 2020

Порядок, в котором вы их вызываете, насколько мне известно, два вызова useEffect в компоненте всегда будут выполняться в одном и том же порядке. Вот как React определяет, какой хук какой (на основе порядка).

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

Эта цитата говорит о порядке вызовов очистки в компонентах и ​​между родительскими и дочерними компонентами. Как правило, то, что вы делаете в части очистки, не должно влиять на другие хуки. Обычно то, что вы делаете, убирает любой длительный побочный эффект в вашем крючке. Такие вещи, как отмена вызовов API и очистка интервалов.

Мы гарантируем, что родительские эффекты уничтожаются раньше, чем дочерние. Причина этого заключается в том, что родители часто имеют тенденцию зависеть от какого-то ресурса, созданного ребенком. Например, удаление слушателя из DOM-узла, которым обязательно управляет ребенок. Если ребенок сначала удаляет свои ресурсы, родитель, возможно, не сможет должным образом очистить себя. Это не указывается c для хуков - это то, как работает componentWillUnmount.

Мы не даем никаких гарантий относительно порядка родственных элементов, будь то внутри компонента или между братьями и сестрами. Это потому, что сильные гарантии мешают рефакторингу. Внутри компонента вы должны иметь возможность переупорядочивать крючки, особенно пользовательские. Ожидается, что между братьями и сестрами вы также можете безопасно переупорядочить их. Также распространено, что только один брат обновляется или отключается, поэтому зависимости между братьями и сестрами не могут быть надежными в любом случае.

Порядок между родителем и дочерним элементом установлен. Например, родительский компонент, который отображает 2 дочерних элемента.

<Parent>
  <Child/>
  <Child/>
</Parent>

Редактировать: так я бы реорганизовал ваш код:

Я бы обязательно включил cb в исходный useRef, а затем используйте cb в массиве зависимостей первого эффекта, чтобы обновить ссылку.

Тогда вы обязательно очистите интервал во втором эффекте.

const Comp = ({ handler }) => {
  // handler is some callback of the form ( ) => void
  useSomeHook(handler);
  //...
};

function useSomeHook(cb) {
  const ref = useRef(cb);

  useEffect(() => {
    ref.current = cb; // update ref before second useEffect
  },[cb]);

  useEffect(() => {
    const id = setInterval(() => {
      ref.current();
    }, 3000); // use the current (most recent) ref value
    return () => {
      clearInterval(id);
    };
  }, []); // run only after first render
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...