Table of Contents
useState
const [state, setState] = useState(initialState);
Возвращает значение с состоянием и функцию для его обновления.
Во время первоначального рендеринга возвращаемое состояние (state
) совпадает со значением, переданным в качестве первого аргумента (initialState
).
Функция setState
используется для обновления состояния. Она принимает новое значение состояния и ставит в очередь повторный рендер компонента.
setState(newState)
;
Во время последующих повторных рендеров первое значение, возвращаемое useState, всегда будет самым последним состоянием после применения обновлений.
Если новое состояние вычисляется с использованием предыдущего состояния, вы можете передать функцию в setState. Функция получит предыдущее значение и вернёт обновлённое значение. Вот пример компонента счётчик, который использует обе формы setState
:
function Counter({ initialCount }) {const [count, setCount] = useState(initialCount);return (<>Счёт: {count}<button onClick={() => setCount(initialCount)}>Сбросить</button><button onClick={() => setCount((prevCount) => prevCount - 1)}>-</button><button onClick={() => setCount((prevCount) => prevCount + 1)}>+</button></>);}
Если функция обновления возвращает абсолютно такой же результат как и текущее состояние, то последующие повторные рендеры будут полностью пропущены. Если вы обновите состояние хука тем же значением, что и текущее состояние, React досрочно выйдет из хука без повторного рендера дочерних элементов и запуска эффектов. (React использует алгоритм сравнения Object.is.) Обратите внимание, что для React всё ещё может быть необходим повторный рендер этого компонента. Это не должно быть проблемой, потому что React не будет сильно «углубляться» в дерево.
useEffect
useEffect(didUpdate);
Принимает функцию, которая содержит императивный код, возможно, с эффектами.
Мутации, подписки, таймеры, логирование и другие побочные эффекты не допускаются внутри основного тела функционального компонента (называемого этапом рендеринга React). Это приведёт к запутанным ошибкам и несоответствиям в пользовательском интерфейсе.
Вместо этого используйте useEffect
. Функция, переданная в useEffect
, будет запущена после того, как рендер будет зафиксирован на экране.
Думайте об эффектах как о лазейке из чисто функционального мира React в мир императивов.
По умолчанию эффекты запускаются после каждого завершённого рендеринга, но вы можете решить запускать их только при изменении определённых значений.
Очистка эффекта
Часто эффекты создают ресурсы, которые необходимо очистить (или сбросить) перед тем, как компонент покидает экран, например подписку или идентификатор таймера. Чтобы сделать это, функция переданная в useEffect
, может вернуть функцию очистки. Например, чтобы создать подписку:
useEffect(() => {document.addEventListener("click", onClickHandler);return () => {// Очистить подпискуdocument.removeEventListener("click", onClickHandler);};});
Функция очистки запускается до удаления компонента из пользовательского интерфейса, чтобы предотвратить утечки памяти.
Кроме того, если компонент рендерится несколько раз (как обычно происходит), предыдущий эффект очищается перед выполнением следующего эффекта.
В нашем примере это означает, что новая подписка создаётся при каждом обновлении. Чтобы избежать воздействия на каждое обновление, обратитесь к следующему разделу.
Порядок срабатывания эффектов
В отличие от componentDidMount
и componentDidUpdate
, функция, переданная в useEffec
t, запускается во время отложенного события после разметки и отрисовки. Это делает хук подходящим для многих распространённых побочных эффектов, таких как настройка подписок и обработчиков событий, потому что большинство типов работы не должны блокировать обновление экрана браузером.
Однако не все эффекты могут быть отложены. Например, изменение DOM
, которое видно пользователю, должно запускаться синхронно до следующей отрисовки, чтобы пользователь не замечал визуального несоответствия. (Различие концептуально схоже с пассивным и активным слушателями событий.) Для этих типов эффектов React предоставляет один дополнительный хук, называемый useLayoutEffect
. Он имеет ту же сигнатуру, что и useEffect
, и отличается только в его запуске.
Хотя useEffect
откладывается до тех пор, пока браузер не выполнит отрисовку, он гарантированно срабатывает перед любыми новыми рендерами. React всегда полностью применяет эффекты предыдущего рендера перед началом нового обновления.
Условное срабатывание эффекта
По умолчанию эффекты запускаются после каждого завершённого рендера. Таким образом, эффект всегда пересоздаётся, если значение какой-то из зависимости изменилось.
Однако в некоторых случаях это может быть излишним, например, в примере подписки из предыдущего раздела. Нам не нужно создавать новую подписку на каждое обновление, а только если изменился проп source
.
Чтобы реализовать это, передайте второй аргумент в useEffect
, который является массивом значений, от которых зависит эффект. Наш обновлённый пример теперь выглядит так:
useEffect(() => {document.addEventListener("click", props.onClickHandler);return () => {// Очистить подпискуdocument.removeEventListener("click", props.onClickHandler);};}, [props.onClickHandler]);
Теперь подписка будет создана повторно только при изменении props.onClickHandler.
Посмотреть 👀
- Введение в React Hooks: useStates
- Введение в React Hooks: useEffect
- React Today and Tomorrow and 90% Cleaner React With Hooks
Почитать 📚
- React hooks: никакой магии, только массивы
- Основные хуки: useState
- Основные хуки: useEffect
- Полное руководство по useEffect
- A Complete Guide to useEffect
Практика 👩💻👨💻
Создать следующие комопоненты:
- Form;
- TodoList;
- Task;
- Компонент
Form
должен содержать следующие поля- name - text
- description - textarea
- duration - range
- add - button type="submit"
По клику на add
форма должна добавить данные в TodoList
и сбросить поля формы в начальное состояние.
- Компонент
TodoList
- должен отображать список задач (компонент Task), если спиоск пуст показывать "Список задач пуст".
- eсли список задач не пустой, отобразить кнопку
Select all
- Компонент
Task
- должен отображать данные с формы
- должен иметь кнопку
Сomplete
(по клику таск должен отмечаться как завершенный) - добавить стили что бы завершенные таски выделялись
- если таск
completed
изменить название кнопки наUncompleted
Компоненты должны быть в следующей иерархии https://codesandbox.io/s/sad-margulis-gnnhj?file=/src/todo/Todo.jsx
ДЗ 🏡
Deck of Cards API DOC
Компонент Используя компонент DeckOfCards Добавить input type=range
Требования
- показывать текущее значение инпута рядом;
- добавить min and max attributes;
- добавить идникатор загрузки данных;
- добавить обработчик ошибок;
При изменении значения инпута список карт должен быть перерисован с тем количеством карт которое указано в инпуте( другими словами, список должен реагировать на изменения в инпуте)
Shuffle the Cards API DOC
Используя Ендпоинт для перемешивания карт
Добавить кнопку Shuffle
, по клику текущий список должен быть перетасован.