#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])