Перейти к содержанию

Правила работы с хуками

Хуки определяются с помощью функций JavaScript, но они представляют собой особый тип многократно используемой логики пользовательского интерфейса с ограничениями на то, где они могут быть вызваны.

Вызывайте хуки только на верхнем уровне

Функции, названия которых начинаются с use, в React называются Hooks.

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

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
function Counter() {
    // ✅ Good: top-level in a function component
    const [count, setCount] = useState(0);
    // ...
}

function useWindowWidth() {
    // ✅ Good: top-level in a custom Hook
    const [width, setWidth] = useState(window.innerWidth);
    // ...
}

Вызов хуков (функций, начинающихся с use) в любых других случаях не поддерживается, например:

  • 🔴 Не вызывайте хуки внутри условий или циклов.
  • 🔴 Не вызывайте хуки после условного оператора возврата.
  • 🔴 Не вызывайте хуки в обработчиках событий.
  • 🔴 Не вызывайте хуки в компонентах классов.
  • 🔴 Не вызывайте хуки в функциях, передаваемых в useMemo, useReducer или useEffect.
  • 🔴 Не вызывайте хуки внутри блоков try/catch/finally.

Если вы нарушите эти правила, вы можете увидеть эту ошибку.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
function Bad({ cond }) {
    if (cond) {
        // 🔴 Bad: inside a condition (to fix, move it outside!)
        const theme = useContext(ThemeContext);
    }
    // ...
}

function Bad() {
    for (let i = 0; i < 10; i++) {
        // 🔴 Bad: inside a loop (to fix, move it outside!)
        const theme = useContext(ThemeContext);
    }
    // ...
}

function Bad({ cond }) {
    if (cond) {
        return;
    }
    // 🔴 Bad: after a conditional return (to fix, move it before the return!)
    const theme = useContext(ThemeContext);
    // ...
}

function Bad() {
    function handleClick() {
        // 🔴 Bad: inside an event handler (to fix, move it outside!)
        const theme = useContext(ThemeContext);
    }
    // ...
}

function Bad() {
    const style = useMemo(() => {
        // 🔴 Bad: inside useMemo (to fix, move it outside!)
        const theme = useContext(ThemeContext);
        return createStyle(theme);
    });
    // ...
}

class Bad extends React.Component {
    render() {
        // 🔴 Bad: inside a class component (to fix, write a function component instead of a class!)
        useEffect(() => {});
        // ...
    }
}

function Bad() {
    try {
        // 🔴 Bad: inside try/catch/finally block (to fix, move it outside!)
        const [x, setX] = useState(0);
    } catch {
        const [x, setX] = useState(1);
    }
}

Вы можете использовать плагин eslint-plugin-react-hooks, чтобы отловить эти ошибки.

Пользовательские хуки могут вызывать другие хуки (в этом и заключается их назначение). Это работает, потому что пользовательские хуки также должны вызываться только во время рендеринга компонента функции.

Вызывайте хуки только из функций React

Не вызывайте хуки из обычных функций JavaScript. Вместо этого вы можете:

✅ Вызывать хуки из компонентов функций React. ✅ Вызывать хуки из пользовательских хуков.

Следуя этому правилу, вы гарантируете, что вся логика с состоянием в компоненте будет четко видна из его исходного кода.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
function FriendList() {
    const [
        onlineStatus,
        setOnlineStatus,
    ] = useOnlineStatus(); // ✅
}

function setOnlineStatus() {
    // ❌ Not a component or custom Hook!
    const [
        onlineStatus,
        setOnlineStatus,
    ] = useOnlineStatus();
}

Источник — https://react.dev/reference/rules/rules-of-hooks

Комментарии