React16: обзор хуков, использование функционального стиля (это, вероятно, самый полный хуки React)

React.js
React16: обзор хуков, использование функционального стиля (это, вероятно, самый полный хуки React)

Хуки были добавлены в React 16.8, что снова сделало функциональные компоненты React возвышенными.Так что же такое хуки?

мотивация

Реагировать на официальный сайта такжеКонференция React в 2018 годуМотивация упомянута выше, так какова же мотивация хуков? Что движет появлением крючков? Давайте сначала посмотрим на мотивацию хуков.

1. Повторное использование логики состояния между компонентами затруднено

React не предоставляет способа «прикрепить» многократно используемое поведение к компонентам. При написании компонентов класса класс является замыканием, и передача состояния между компонентами не очень удобна, хотя для решения этой проблемы можно использовать реквизиты и компоненты более высокого порядка. , но это сделает структуру компонента более громоздкой. Если вы посмотрели на приложения React в React DevTools, вы увидите, что компоненты, состоящие из провайдеров, потребителей, компонентов более высокого порядка, реквизитов рендеринга и других слоев абстракции, образуют «вложенный ад».

2. Сложные компоненты становятся трудными для понимания

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

3. Непонятные занятия

В документе говорится, что это в основном потому, что обучение в классе является трудным моментом. Поскольку я некоторое время пишу класс es6, класс меня все еще устраивает, и это понимание в порядке.

Что такое крючки?

Итак, что такое Крюк, Крюк, как следует из названия, означает крючок. В функциональном компоненте состояние и жизненный цикл React связаны с функциональным компонентом, который является крючком React.

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

Правила использования хуков

Hook — это функция javascript, но она использует два правила:

  1. Хуки можно вызывать только из самого внешнего слоя функции. Не вызывайте его в циклах, условных выражениях или подфункциях. (Это связано с механизмом выполнения хуков, который будет упомянут в хуке ниже)
  2. Хуки можно вызывать только из функциональных компонентов React. Не вызывайте его в других функциях javascript (также можно вызывать в пользовательских хуках)

Преимущества использования хуков

  1. Используя хуки, если бизнес меняется, нет необходимости изменять функциональный компонент в компонент класса.
  2. Попрощайтесь со сложным этим и объедините забытый жизненный цикл.
  3. Поддержка создания собственных хуков (пользовательских хуков), основанных на чистом императивном API.
  4. Лучше выполнено совместное использование между состояниями, решена проблема внутренней инкапсуляции исходного компонента класса, а также решена глубокая вложенность компонентов более высокого порядка и функциональных компонентов. Компонент имеет свое собственное состояние, которое может использоваться внутри компонента.

Встроенный крючок

React имеет в общей сложности 9 встроенных хуков.

  • useState
  • usEffect
  • useContext
  • useReducer
  • useCallback
  • useMemo
  • useRef
  • useImperativeHandle
  • useLayoutEffect

useState

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

State Hooks теперь позволяют функциональным компонентам использовать состояние.

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

import React, { useState } from "react";

const Greeting = () => {
    const states = useState(0);
    const count = states[0];
    const setCount = states[1];
    return (
       <>
            <h1> {count} </h1>
            <button onClick={() => {setCount(count + 1)}}> + </button>
       </>
    )
}
export default Greeting;

Слишком хлопотно каждый раз брать первый элемент массива, поэтому официально рекомендуется использовать метод деструктурирующего присваивания массива ES6.

const [count, setCount] = useState(1);

Похоже, это намного проще. Обновить код

import React, { useState } from "react";
const Greeting = () => {
    const [count, setCount] = useState(0);
    return (
       <>
            <h1> {count} </h1>
            <button onClick={() => {setCount(count + 1)}}> + </button>
       </>
    )
}
export default Greeting;

Мы обнаружили, что после завершения вызова общей функции переменные в ней будут переработаны, и из приведенного выше кода и рисунка видно, что каждый разcountБаза добавляется, а она не исчезает, почему? Сначала закопайте вопрос, который будет упомянут в механизме исполнения Крюка.

Используйте useState несколько раз

Мы не можем иметь только одно состояние в компоненте, useState позволяет использовать его несколько раз в компоненте, и каждое использование является совершенно новым состоянием.

import React, { useState } from "react";
const Greeting = () => {
    const [count, setCount] = useState(0);      //第一次使用
    const [istrue, setIstrue] = useState(true); //第二次使用
    return (
       <>
            {istrue ? <h1> {count} </h1> : void 0}
            <button onClick={ () => {setIstrue(!istrue)}}>change</button>
            <button onClick={() => {setCount(count + 1)}}> + </button>
       </>
    )
}
export default Greeting;

В приведенном выше коде дважды используется useState, что идеально завершает функцию.

Итак, теперь у меня есть вопрос, как React различает хуки, которые вызываются несколько раз? Сначала закопайте вопрос, который будет обсуждаться при механизме исполнения хука (все хуки такие).

useEffect

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

React Hooks предоставляет Effect Hook, который может выполнять операции с побочными эффектами в функциональных компонентах и ​​выполнять операции с побочными эффектами после того, как функция визуализирует DOM.

import React, {useEffect} from "react";

Метод useEffect передает функцию в качестве параметра, выполняет код побочного эффекта в функции, а первый параметр useEffec также поддерживает возвращаемое значение функции, что эквивалентно обновлению и удалению компонента.

import React, {useState, useEffect} from "react";

const EffectComponent = () => {
    useEffect(() => {
        console.log("useEffect Hook");
    })
    return null;
}
export default EffectComponent

Сравнение с жизненным циклом компонента класса

Все мы знаем, что в компонентах класса мы можемcomponentDidMountа такжеcomponentDidUpdateВыполнение побочных эффектов в функциональном компоненте, тогда функция параметра useEffect в функциональном компоненте имеет цель этих двух жизненных циклов компонента класса.Если первый параметр useEffec имеет возвращаемое значение функции, возвращаемое значение функция эквивалентнаcomponentWillUnmount. Можно сказать, что useEffect объединяет эти три API в один.

Наиболее распространенным способом является запись регистрации события в параметрах функции и запись уничтожения события в функции возврата функции.

import React, {useState, useEffect} from "react";

const EffectComponent = () => {
    const [width, setWidth] = useState(window.innerWidth);
    const resizeHandle = () => {
        setWidth(window.innerWidth);
    }
    useEffect(() => {
        window.addEventListener("resize", resizeHandle);
        return () => {
            window.removeEventListener("resize", resizeHandle)
        }
    })
    return (
        <h1>{width}</h1>
    );
}
export default EffectComponent

Время выполнения useEffect

Из вышеизложенного мы знаем, что useEffect можно назвать комбинацией трех жизненных циклов в компонентах класса, но каково время его выполнения? Из небольшой демонстрации

import React, {useState, useEffect} from "react";
const EffectComponent = () => {
    const [count, setCount] = useState(1);
    useEffect(() => {
        console.log("定义事件接口")
        return () => {
            console.log("注销事件接口")
        }
    })
    return (
        <>  
            {console.log("渲染")}
            <h1>{count}</h1>
            <button onClick={() => {setCount(count + 1)}}> + </button>
        </>
    );
}
export default EffectComponent

В начале упоминалось, что useEffec выполняет побочные эффекты после рендеринга, что действительно так. Если вы будете осторожны, вы обнаружите, что когда я нажимаю знак +, как он может появиться?注销事件接口? Разве функция возврата в функции useEffec не вызывается, когда компонент выгружается?

Мое личное понимание состоит в том, что разрушение, представленное функцией return в параметре функции useEffec, является уничтожением самого useEffect, и новый Effec будет регенерироваться каждый раз при повторном выполнении функционального компонента. Если он не уничтожен, потому что параметры функции useEffect будут вызываться при его первом рендеринге и обновлении, это имеет фатальный недостаток: если я определяю событие, оно будет выполняться при каждом обновлении, то оно не будет удалено. до того, как событие будет удалено, оно определено снова, поэтому useEffect добавляет эту функцию.

Мы смотрим, чтобы подтвердить вышеупомянутое обсуждение правильное.

import React, {useState, useEffect} from "react";

const EffectComponent = () => {
    const [width, setWidth] = useState(window.innerWidth);
    const [count, setCount] = useState(1);
    const resizeHandle = () => {
        setWidth(window.innerWidth);
        console.log(window.innerWidth);
    }
    useEffect(() => {
        window.addEventListener("resize", resizeHandle);
        return () => {
            // window.removeEventListener("resize", resizeHandle)
        }
    })
    return (
        <>
            <h1>{count}</h1>
            <button onClick={() => {setCount(count + 1)}}>+</button>
        </>
    );
}
export default EffectComponent

В приведенном выше коде я удалил и закомментировал возвращаемое событие в useEffect и напечатал ширину окна в обработчике событий.Видно, что когда я запускаю событие окна в первый раз, оно сразу печатается три раза.

Второй параметр useEffect

Когда второй параметр useEffect не записан (не записан выше), любое обновление вызовет useEffect. Затем поговорим о втором параметре useEffect.

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

Когда массив пуст, useEffect эквивалентенcomponentDidMoubtа такжеcomponentWillUnmountЭти два жизненных цикла выполняются только во время первого рендеринга и выгрузки.

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

const EffectComponent = () => {
    const [count, setCount] = useState(1);
    const [num, setNum] = useState(2);
    useEffect(() => {
        console.log("count状态更新");
        return () => {
            console.log("useEffect卸载")
        }
    },[count])
    return (
        <>
            <h1>{count}</h1>
            <button onClick={() => {setCount(count + 1)}}>+</button>
            <h1>{num}</h1>
            <button onClick={() => {setNum(num + 1)}}>+</button>
        </>
    );
}

Напишите несколько useEffects

Когда мы пишем компоненты класса, мы обычно определяем события вcomponentDidMount, если это просто обработка событий, ничего страшного, если проект не большой, тогда, если проект большой, вся обработка событий определяется жизненным циклом, не запутанно? Хаос неизбежен, и он также подвержен ошибкам.

React Hook позволяет определять несколько useEffects (аналогично useState) в функциональных компонентах, и несколько useEffects не мешают друг другу.

const EffectComponent = () => {
    const [count, setCount] = useState(1);
    const [num, setNum] = useState(2);
    useEffect(() => {
        console.log("count状态更新");
        return () => {
            console.log("count卸载")
        }
    },[count])
    useEffect(() => {
        console.log("num状态更新");
        return () => {
            console.log("num卸载")
        }
    },[num])
    return (
        <>
            <h1>{count}</h1>
            <button onClick={() => {setCount(count + 1)}}>+</button>
            <h1>{num}</h1>
            <button onClick={() => {setNum(num + 1)}}>+</button>
        </>
    );
}

useEffect играет очень важную роль в функциональных компонентах, и при правильном использовании он станет артефактом.

useContext

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

Хуки, которые также реагировали на Context API после появления React HooksuseContext. Это также проблема расшифровки значения.

Хук useContext принимает объект контекста (объект, созданный createContext ) в качестве параметра и возвращает Context.Consumer. Например:

const stateContext = createContext('default');
  • Правильно: useContext(stateContext)
  • Ошибка: useContext(stateContext.Consumer)
  • Ошибка: useContext(stateContext.Provider)

Как использовать

Например, есть простой компонент ContextComponent

const ContextComponent = () => {
    return (
        <>
            <h1>{value}</h1>
        </>
    );
}

Отправьте информацию этому компоненту через Context API.

export default () => (
    <stateContext.Provider
        value={"Hello React"}
    >
        <ContextComponent/>
    </stateContext.Provider>
)

использовать useContext()

const value = useContext(stateContext);

Использование useContext должно быть в функциональном компоненте, иначе будет сообщено об ошибке.

Как видно, по-прежнему необходимо использовать useContext в верхнем компоненте, чтобы предоставить контекст для нижележащих компонентов.

useReducer

ВидетьuseReducer, обязательно подумает о Redux, да, он работает так же, как Redux. Появление useReducer — это альтернатива useState, которая позволяет нам лучше управлять состоянием.

useReducer может принимать в общей сложности три параметра и возвращать текущее состояние и соответствующую отправку.

первый параметр

Первый параметр useReducer имеет вид(state,action) => newStateТакой редьюсер, да, редьюсер, это точно такой же редукс. Давайте определим простой редуктор.

const reducer = (state, action) => {
    switch(action.type){
        case "ADD_TODO":
            return [
                ...state,
                action.todo
            ];
        default:
            return state;

    }
}

Вышеупомянутый простой редуктор Если вы будете осторожны, вы обнаружите, что параметру состояния не нужно указывать значение по умолчанию? Нет, React не нужно указыватьstate = initialState, иногда начальное значение нужно зависеть от пропса, поэтому начальное значение указывается на useReducer, может уже догадались, какой второй параметр?

второй параметр

Второй параметр useReducer такой же, как createStore Redux, указывающий значение состояния по умолчанию. Например:

useReducer(reducer,[{
    id: Date.now(),
    value: "Hello react"
}])

третий параметр

Третий параметр useReducer принимает функцию в качестве параметра и выполняет второй параметр в качестве параметра функции. Основная функция — ленивая оценка начального значения, которая извлекает часть логики состояния, что способствует сбросу состояния.

определить функцию инициализации

function init(initialCount) {
    return [
        ...initialCount,
    ];
}

useReducer использует

useReducer(reducer,[
        {
            id: Date.now(),
            value: "Hello react"
        }
    ],init)

useReducer возвращаемое значение

Возвращаемое значение useReducer представляет собой массив, первый элемент массива — текущее состояние, а второй элемент — отправка, соответствующая текущему состоянию.Вы можете использовать присваивание деструктурирования ES6, чтобы получить эти два

const [state,dispatch] = useReducer(reducer,[
    {
        id: Date.now(),
        value: "Hello react"
    }
],init)

Неглубокий сравнительный рендеринг

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

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

Начнем с добавления case в редьюсер, который изменяет значение Todo.

case "CHANGE_TODO":return state[action.id] = 'change' && state;

Измените возврат и передайте атрибут изменения нижнему компоненту.

const change = (id) => {
    dispatch({
        type: "CHANGE_TODO",
        id,
    })
}
return (
    <>
        <button onClick={() => {dispatch({type: "ADD_TODO",todo:{id:Date.now(),value:"Hello Hook"}})}}> Add </button>
        {state.map((todo,index) => (
           <Todo key={index} todo={todo.value} change={()=>{change(todo.id)}}/>
        ))}
    </>
)

Добавьте событие щелчка в компонент Todo. Когда щелчок вызывает метод из верхнего компонента, значение компонента изменяется.

let Todo = ({todo,change}) => {
    return (
        console.log("render"),
        <li onClick={change}>{todo}</li>
    );
}

Как вы можете видеть на картинке, независимо от того, как я нажимаю на li, он не меняется.

Итак, давайте изменим редьюсер, чтобы он возвращал совершенно новый массив.

case "CHANGE_TODO":
    return state.map((todo,index) =>{
        if(todo.id === action.id){
            todo.value="change";
        }
        return todo;
    } )

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

useCallback

useCallback можно рассматривать как прослушиватель зависимостей. Он принимает функцию обратного вызова и массив зависимостей и возвращает запомненную (в памяти) версию функции обратного вызова. Функция обратного вызова будет обновляться только при изменении зависимости.

Простой небольшой пример

const CallbackComponent = () => {
    let [count, setCount] = useState(1);
    let [num, setNum] = useState(1);
    
    const memoized = useCallback( () => {
        return num;
    },[count])
    console.log("记忆:",memoized());
    console.log("原始:",num);
    return (
        <>
            <button onClick={() => {setCount(count + 1)}}> count+ </button>
            <button onClick={() => {setNum(num + 1)}}> num+ </button>
        </>
    )
}

Если массив зависимостей не передается, мемоизированная функция будет обновляться при каждом рендеринге.

useMemo

useMemo похож на useCallback, с той лишь разницей, что

useCallback(fn, deps) эквивалентно useMemo(() => fn, deps

Не так много, чтобы представить здесь.

useRef

React16 появился в наличииObject.createRefСпособ создания реф, так там тоже такой хук.

Используйте синтаксис:

const refContainer = useRef(initialValue);

useRef возвращает изменяемый объект ref, useRef принимает параметр, привязанный к текущему свойству возвращенного объекта ref, а возвращенный объект ref остается неизменным на протяжении всего жизненного цикла.

Каштан:

const RefComponent = () => {
    let inputRef = useRef(null);
    useEffect(() => {
        inputRef.current.focus();
    })
    return (
        <input type="text" ref={inputRef}/>
    ) 
}

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

useImperativeHandle

useImperativeHandle позволяет настроить значение экземпляра, предоставляемое родительскому компоненту при использовании ref.

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

Как использовать

useImperativeHandle(ref, createHandle, [deps])

Каштан:

function FancyInput(props, ref) {
    const inputRef = useRef();
    useImperativeHandle(ref, () => ({
        focus: () => {
            inputRef.current.value="Hello";
        }
    }));
    return <input ref={inputRef} />;
}
FancyInput = forwardRef(FancyInput);

export default () => {
    let ref = useRef(null);
    useEffect(() => {
        console.log(ref);
        ref.current.focus();
    })
    return (
        <>
            <FancyInput ref={ref}/>
        </>
    )
}

Выше приведен пример передачи ссылки в компонентах «родитель-потомок» с использованием forwardRef (это функция более высокого порядка, в основном используемая для передачи ссылки в компонентах «родитель-потомок») с использованием useImperativeHandle для привязки возвращаемого значения второго параметра к родительский компонент для передачи Давай, ссылка.

useLayoutEffect

Эта функция ловушки аналогична useEffect и используется для выполнения побочных эффектов. Но он будет вызывать эффект синхронно после всех изменений DOM. Самая большая разница между useLayoutEffect и useEffect заключается в том, что один из них является синхронным, а другой — асинхронным.

Как видно из названия этого хука, он в основном используется для чтения макета DOM и запуска синхронного рендеринга.Прежде чем браузер выполнит отрисовку, план обновления внутри useLayoutEffect будет обновлен синхронно.

Официальный сайт рекомендует максимально использовать стандартный useEffec, чтобы избежать блокировки визуальных обновлений.

Крючковый исполнительный механизм

Всего 2 вопроса.

Первый: после вызова функции переменные в функции будут очищены, но как ReactHook повторно использует состояние?

React отслеживает, какие компоненты в данный момент рендерятся, и у каждого компонента есть список «ячеек памяти» внутри него. Это не что иное, как объекты JavaScript, которые мы используем для хранения некоторых данных. Когда вы вызываете хук с помощью useState(), он считывает текущую ячейку (или инициализирует ее при первом рендеринге) и перемещает указатель на следующую. Вот почему несколько вызовов useState() получают собственное независимое локальное состояние.

Причина, по которой он называется не createState, а useState, заключается в том, что состояние создается только при первом отображении компонента. При следующем повторном рендеринге useState возвращает нам текущее состояние.

    const [count, setCount] = useState(1);
    setCount(2);
    //第一次渲染
        //创建state,
        //设置count的值为2
    //第二次渲染
        //useState(1)中的参数忽略,并把count赋予2

Как React различает хуки, которые вызываются несколько раз, и как узнать, что этот хук предназначен для этой цели?

React зависит от порядка вызова хуков. Хуки вызываются в одном и том же порядке каждый раз в функциональном компоненте. На примере с официального сайта:

// ------------
// 首次渲染
// ------------
useState('Mary')           // 1. 使用 'Mary' 初始化变量名为 name 的 state
useEffect(persistForm)     // 2. 添加 effect 以保存 form 操作
useState('Poppins')        // 3. 使用 'Poppins' 初始化变量名为 surname 的 state
useEffect(updateTitle)     // 4. 添加 effect 以更新标题

// -------------
// 二次渲染
// -------------
useState('Mary')           // 1. 读取变量名为 name 的 state(参数被忽略)
useEffect(persistForm)     // 2. 替换保存 form 的 effect
useState('Poppins')        // 3. 读取变量名为 surname 的 state(参数被忽略)
useEffect(updateTitle)     // 4. 替换更新标题的 effect

// ...

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

Если есть крюк, написанный в заявлении о суждении

if (name !== '') {
    useEffect(function persistForm() {
      localStorage.setItem('formData', name);
    });
}

В приведенном выше примере, если имя является значением, которое необходимо отправить, при первом рендеринге имя не существует как истинное, поэтому первый порядок выполнения HOOK

useState('Mary')           // 1. 使用 'Mary' 初始化变量名为 name 的 state
useEffect(persistForm)     // 2. 添加 effect 以保存 form 操作
useState('Poppins')        // 3. 使用 'Poppins' 初始化变量名为 surname 的 state
useEffect(updateTitle)     // 4. 添加 effect 以更新标题

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

useState('Mary')           // 1. 读取变量名为 name 的 state(参数被忽略)
// useEffect(persistForm)  // 🔴 此 Hook 被忽略!
useState('Poppins')        // 🔴 2 (之前为 3)。读取变量名为 surname 的 state 失败
useEffect(updateTitle)     // 🔴 3 (之前为 4)。替换更新标题的 effect 失败

Это приведет к появлению багов. Следовательно, при написании хука он должен быть написан на самом внешнем слое функционального компонента, а не в суждении или цикле.

Пользовательский крючок

Пользовательские хуки можно назвать соглашением, а не функцией. когда функция начинается сuseЗапустите и вызовите другие хуки внутри функции, затем эта функция может стать пользовательскими хуками, такими какuseSomething.

Пользовательские хуки могут инкапсулировать состояние и лучше обеспечивать совместное использование состояния.

Давайте инкапсулируем цифровое дополнение к крючку вычитания

const useCount = (num) => {
    let [count, setCount] = useState(num);
    return [count,()=>setCount(count + 1), () => setCount(count - 1)]
};

Этот пользовательский хук использует UseState, определяет состояние, возвращает значение значения в массиве, состояние массива, функцию ++ и функцию.

const CustomComp = () => {
    let [count, addCount, redCount] = useCount(1);

    return (
        <>
            <h1>{count}</h1>
            <button onClick={addCount}> + </button>
            <button onClick={redCount}> - </button>
        </>
    )
}

Основная функция использует назначение деструктурирования, чтобы принять эти три значения, что является очень простым пользовательским хуком. Если проект большой, использование пользовательского хука позволит извлечь общедоступный код, что значительно сократит объем нашего кода и повысит эффективность разработки.

Суммировать

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