Использование hook в качестве функции обратного вызова

#reactjs #react-hooks

Вопрос:

Я знаком с Правилами крючков, с причиной правил (гарантируя, что крючки всегда вызываются в одном и том же порядке) и с eslint предупреждением.

В некоторых случаях, когда функция обратного вызова сама по себе является крючком, а не функцией стрелки, eslint предупреждение исчезает. См. Пример кода ниже.

Пример

Вот какой-то код с кодовым полем. (Предупреждение: Придуманный и ничего не делающий код впереди).

 import React from "react";

export default function App() {
  const list = ["a", "b", "c"];

  // The call to useSomething() could be made in ListItem,
  // and it would certainly be cleaner.
  // However, it is made here intentionally,
  // to demonstrate that there is no eslint
  // warning and no error from React when the callback
  // for map() is declared as a custom hook.

  const transformed = list.map(function useCb(val) {
    return useSomething(val);
  });

  return (
    <>
      <h2>
        Hook as <code>Array.map()</code> callback
      </h2>

      <ul>
        {transformed.map((val, i) => {
          return <ListItem key={i} val={val} />;
        })}
      </ul>
    </>
  );
}

/**
 * Trivial example of custom hook with reusable state logic,
 * for demonstration purposes.
 * A real hook would be more complex and do something sensible.
 */
function useSomething(val) {
  const [state, setState] = React.useState(null);

  React.useEffect(() => {
    // Do something with `val`.
    // Store result in state.
    setState(`result of `useEffect()` on `${val}``);
  }, [val]);

  return React.useMemo(() => `Expensive tranformation to ${state}`, [state]);
}

function ListItem({ val }) {
  return <li>{val}</li>;
}

 

В Правилах говорится:

Не вызывайте крючки внутри циклов, условий или вложенных функций. Вместо этого всегда используйте крючки на верхнем уровне вашей функции React, прежде чем какие-либо ранние возвраты.

Предполагая, что «верхний уровень» означает верхнюю часть стека вызовов, а не вложенную:

Я бы сказал, что в этом случае вызов useCb() не находится на верхнем уровне функции React , потому что он вложен Array.map() и также находится в цикле. Я считаю Array.map() , что это петля.

Итак, я бы сказал, что эта реализация нарушает Правила Крючков.

Стандартное eslint предупреждение гласит::

Крючок реакции «<имя_цепа>» не может быть вызван внутри обратного вызова. Крючки реакции должны вызываться в компоненте функции реакции или пользовательской функции крюка реакции. (реагирующие крючки/правила крючков)

Для меня это подразумевает взаимное исключение, например: «Если это в компоненте функции React или пользовательской функции крючка React, то это не внутри обратного вызова и, следовательно, нормально».

Но в этом случае я бы сказал, что useSomething() крючок вызывается внутри обратного useCb() вызова , который также является пользовательской функцией React Hook.

Я понимаю, почему это может быть рискованной, «плохой идеей». Если list он динамичен, то количество вызовов с подключением может измениться.

Но если это нарушает Правила крючков и в противном случае является рискованной плохой идеей, почему нет предупреждения о линтинге или ошибки реакции о неправильном использовании крючка?

Является ли это просто случаем упущений при проверке ошибок и / или двусмысленности в словах? Или это законная реализация для редких крайних случаев, когда порядок и количество вызовов соединений не меняются? Или что-то еще?

Комментарии:

1. Я полагаю, что это только «искажает» правила и не нарушает их напрямую, хотя, если длина массива когда-либо изменится, вы увидите одну из других ошибок в крючках, связанных с изменением порядка крючков между рендерами.

2. @DrewReese Точно. Если list это динамично, это может привести к проблемам, которые должны предотвращаться Правилами крючков. Так что, вероятно, в большинстве случаев это рискованная, плохая идея. И в этом суть моего вопроса… Нет никаких предупреждений о вставках или ошибок реагирования. Означает ли это, что, как правило, все «в порядке», или это означает, что проверка на ошибки недостаточна?

3. Ну, предупреждения о ворсе появляются в результате статического анализа кода, ошибки реакции возникают из-за исключений во время выполнения. Это что-то вроде Яблок и Апельсинов.

4. Я понимаю. Но в подобных случаях может произойти и то, и другое. Если бы я использовал этот шаблон при useEffect обратном вызове, React отобразил бы ошибку в режиме разработки со стандартным всплывающим окном ошибки, которое затемняет страницу. И реагируйте на StrictMode ошибки, когда он обнаруживает разницу в количестве или порядке крючков. Я хочу сказать, что ни плагин linting, ни встроенная проверка ошибок React не имеют проблем с этой реализацией.

5. useEffect(function useCb() { useSomething(val) }, [val])