
Выясним, что такое локальное состояние и как им эффективно управлять.
Что такое локальное состояние
Если вы работали с предыдущими версиями Next.js или React, некоторые из рассматриваемых здесь понятий вам уже будут знакомы. Тем не менее начнем с базового понятия: локальное состояние — это данные, управляемые в рамках конкретного компонента.
Речь идет об отслеживании информации на уровне компонента, чтобы все в приложении сохраняло организованность и функциональность.
Локальное состояние может варьироваться от чего-то простого (например тумблера) до чего-то более сложного (например управления значениями формы). «Локальным» оно называется потому, что определяется, используется и обновляется исключительно в рамках одного компонента.
Важно понимать: чтобы данные считались локальным состоянием, они должны полностью управляться создающим их компонентом. Никакому другому компоненту не нужен доступ к ним, что делает их полностью самодостаточными.
Шаблоны управления локальным состоянием
Для инициализации локального состояния React предоставляет хук «useState».
При использовании хука «useState» возвращается пара: текущее значение состояния и функция для обновления этого значения.
Рассмотрим механизм работы хука «useState» на примере кода, представленного ниже.
const [count,setCount] = useState(0)
Итак, у нас есть переменная состояния «count», инициализированная нулем. Это наша отправная точка. Теперь сосредоточимся на том, что здесь происходит. Такой синтаксис известен как деструктуризация массива.
Тем, кто не знаком с этим термином, поясню: при вызове хука «useState» фактически возвращается массив значений. Только и всего — никаких скрытых сложностей.
Использование синтаксиса деструктуризации JavaScript позволяет присваивать значения, возвращаемые «useState», локальным независимым переменным. Первое значение представляет собой текущее состояние, присвоенное нами константе «count». Это позволяет легко ссылаться на состояние и работать с ним непосредственно в коде.
Второе значение, возвращаемое «useState», всегда является функцией-сеттером — функцией, используемой для обновления состояния. Как вы знаете, переменную состояния нельзя обновлять напрямую.
Например, здесь мы не можем напрямую изменить «count». Вместо этого для корректной обработки обновлений будем использовать функцию-сеттер.
Нельзя просто присвоить «count = 1», даже если переменная была объявлена посредством «let» вместо «const». Такое ограничение объясняется тем, что React должен повторно рендерить компонент при каждом изменении состояния.
React полагается на функцию-сеттер, чтобы отслеживать эти обновления и запускать процесс повторного рендеринга, гарантируя синхронизацию.
Чтобы избежать потенциальных ловушек в коде, разумным подходом будет объявить эти два значения — эти переменные — как константы. Это означает отказ от использования «let» или, что еще хуже, устаревшего ключевого слова «var».
Такой подход гарантирует следующее: если вы случайно напишете код, который может переназначить значение переменной «count», интерпретатор немедленно отметит это как ошибку. В конце концов, константы неизменяемы после инициализации, и пытаться изменить их просто недопустимо.
Это простая, но ценная практика стоит того, чтобы вы внедрили ее в свои проекты. Она лишний раз подтверждает, что управление локальным состоянием — вполне доступный процесс.
Воспользуемся функцией-сеттером, предоставляемой хуком «useState». Этот шаг очень важен, потому что React должен быть проинформирован об обновлении состояния, чтобы вызвать необходимый повторный рендеринг компонента.
Наш простой компонент «Counter» («Счетчик») использует функцию-сеттер для обновления переменной «count» при каждом клике. С каждым кликом значение счетчика увеличивается, и отображаемое значение плавно обновляется.
setCount(count + 1)
Это работает, потому что весь компонент повторно рендерится при каждом обновлении состояния. И последнее замечание по поводу хука «useState»: практически во всех примерах и React-проектах функция-сеттер для переменной состояния должна соответствовать соглашению об именовании. Она всегда называется «set», после чего следует заглавная буква имени переменной состояния.
В данном случае функция-сеттер называется «setCount», потому что переменная состояния называется «count». Эта практика, основанная всего лишь на соглашении об именовании, широко принята, поскольку помогает понять, что функция-сеттер предназначена для конкретной переменной состояния.
На самом деле, поскольку React предоставляет прямой доступ к функции-сеттеру как ко второму значению в массиве, возвращаемому «useState», вы можете назвать ее как угодно. Соглашение об именовании используется только для ясности и последовательности.
Скажем прямо: это просто полезное соглашение об именовании. Следование ему облегчит вам жизнь. Однако вы не обязаны слепо придерживаться этого соглашения об именовании; можете изменять или адаптировать его по мере необходимости в соответствии с вашими предпочтениями.
Еще один важный момент: значение, передаваемое хуку «useState», служит начальным значением для переменной состояния.
Можно передать туда прямое значение JavaScript, например объект или массив — что угодно. Но также можно просто использовать пропсы. Например, очень распространенной практикой является использование пропсов компонента в качестве четырех значений для переменных состояния.
Можно даже сделать кое-что более сложное, а именно: определить функцию, как показано ниже в примере кода. Эта функция будет вызываться всякий раз при определении переменной состояния и возвращать начальное значение.
const Counter = () => {
const [count,setCount] = useState(0)
return (
<div>
<p>Your count is now {count}</p>
<button onClick={() => setCount(count + 1)}>
Click me
</button>
</div>
)
}
Можно реализовать такие сложные операции, как получение значения из другого места в DOM или выполнение синхронных вычислений. Только помните, что они должны быть синхронными. И что бы вы ни делали, учтите: эта функция будет вызвана всего один раз.
После первого рендеринга компонента и первого определения переменной состояния функция-сеттер вызывается при каждом последующем обновлении состояния и повторном рендеринге компонента.
Этот шаг будет проигнорирован, потому что React уже будет знать текущее значение переменной состояния и не будет заменять его этой функцией.
В примере кода, приведенного ниже, показан весь компонент, который использует по начальное значение состояния тумблера по умолчанию, причем тумблер — переменная локального состояния.
Внедрите в свои компоненты эту распространенную практику, чтобы при каждом взаимодействии с кнопкой состояние менялось и компонент повторно рендерился.
const Toggle= ({intialValue}) => {
const [toggle,setToggle] = useState(intialValue)
return (
<div>
<button onClick={() => setToggle(!toggle)}>
{toggle ? "ON": "OFF"}
</button>
</div>
)
}
Значение тумблера будет включаться и выключаться, но начальное значение больше не будет запоминаться. Однако при первом рендеринге желательно иметь возможность управлять состоянием с помощью пропсов.
Подведем итоги
Локальное состояние — основа интерактивности компонентов. Всякий раз при обновлении локального состояния компонент повторно рендерится. Хук «useState» предоставляет мощный и интуитивно понятный способ управления динамической информацией.
Вы можете определять значения по умолчанию, используя как угодно сложную логику для определения этих значений. Поэтому не забывайте инициализировать переменные состояния.
К обновлению состояния следует подходить ответственно, четко понимая, когда необходимо это обновление и как оно повлияет на компонент.
И последнее, но не менее важное: помните, что обновление — асинхронный процесс. Если вы все это учтете, ваши компоненты всегда будут реагировать на взаимодействия, не вызывая снижения производительности всего приложения.
Читайте также:
- Потрясающие функции Next.js 15
- 5 практик, которые облегчат работу с Next.js 14
- Разделение кода в Next JS
Читайте нас в Telegram, VK и Дзен
Перевод статьи Imran Farooq: Next.js State Management Patterns With React Server Components (Ep 6)