Почему не стоит всегда использовать «useState»

Здравствуйте, я фронтенд-разработчик и хочу поделиться своим мнением о том, почему не стоит всегда использовать useState.

Почему не стоит всегда использовать «useState»

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

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

Почему я люблю useRef?

1 - useState

Посмотрите на пример ниже

Почему не стоит всегда использовать «useState»

Вы знаете, что произойдет?

useState является асинхронным хуком, он будет ждать завершения цикла компонента, повторного рендеринга, а затем обновит состояние. Таким образом, userToken (строка 20) будет пустой строкой.

2 - useRef

Когда мне нужно сделать что-то сразу и это необходимо для потока моего кода, тогда я выбираю useRef. Почему? Потому, что он сохраняет значение на протяжении всего жизненного цикла компонента, но самое интересное, что он синхронный!

Давайте перепишем пример выше и заставим его работать!

Почему не стоит всегда использовать «useState»

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

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

3 - обычная переменная

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

Почему не стоит всегда использовать «useState»

Как работает useState

Я сделал иллюстрацию кода, чтобы объяснить, как работает хук useState под капотом.
Если вы когда-нибудь слышали о замыкании, то это покажется вам знакомым.

Почему не стоит всегда использовать «useState»

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

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

Как он сохраняет значение состояния при повторных рендерингах компонента? Все дело в замыкании.

Замыкания дают нам возможность создавать функции с "памятью", которая сохраняется, что означает, что при повторном выполнении функции у нее будет ссылка на предыдущее выполнение. Давайте объясню:

const playGame = () => { let counter = 0; const increment = () => { if(counter === 9){ console.log("Don't you have something better to do?") return } counter+=1 console.log(counter) } return increment; } const onClick = playGame(); onClick() onClick() onClick() onClick() onClick() onClick() onClick() onClick() onClick() onClick()

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

Спасибо, что прочитали статью!

22
5 комментариев

В большом приложении лучше вообще не использовать хуки. Я предпочитаю mobx. По мне дак верстка и функционал не должны быть внутри одного компонента

1

Mobx мне показался очень удобным. Недавно с ним довелось поработать, после redux - одно удовольствие)

Почему сначала происходит рендеринг, а за ним изменение состояния, если компонент рендерится с уже новым значением?

1

Почему в примере самописного useState state - это функция?