Привет Хабр! Как вы знаете при переходе с компонентов классов на функциональные, у нас отняли такую полезную вещь как this, которая указывает на текущий экземпляр компонента. И конечно у нас возник вопрос: “а где же тогда хранить timeoutId?”. И я видел как люди по разному выкручивались из этой проблемы (Данная статья, является расшифровкой видео) Например, если timeoutId используется только в рамках одного useEffect можно набросать следующий вариант: Данный подход работает, но когда появляется нужда очищать timeout по клику на кнопку, этот подход уже не работает. Поэтому многие решили, просто создавать переменную вне компонента и хранить в ней id этого тайм-аута, чтобы например по клику иметь возможность его отменить:  И это работает в большинстве случаев без каких-либо проблем. Но как всегда есть “НО”. Давайте рассмотрим пример. Допустим у нас есть компонент Counter, в котором есть локальный счетчик и глобальный счетчик определенный вне компонента: Компонент достаточно простой. Теперь добавим родительский компонент: Здесь мы храним в state количество счетчиков, и ниже имеем 2 кнопки: для увеличения количества счетчиков и для уменьшения. И собственно вставляем сами счетчики в таком количество, как у нас указано в переменной countersNumber. Перейдем в браузер и выполним следующие действия: Добавим один счетчик; Внутри появившегося счетчика, нажмем "increment" три раза; Добавим второй счетчик. Как вы видите у второго глобального каунтера значение три. И не важно сколько счетчиков вы создадите, они все замыкаются на одну и ту же глобальную переменную. И даже если вы удалите все счетчики, а потом добавите новый счетчик, конечно же глобальный каунтер все равно будет равен трем, так как глобальная переменная создается при запуске сайта и очищается при полном закрытии табы в браузере с вашим сайтом. Таким образом, хранение timeoutId в такого рода глобальной переменной, может привести к странным багам. Да и если у вас в проекте огромное количество таких переменных, вы бесполезно засоряете память вашего компьютера, хоть это возможно и экономия на спичках. Решением данной проблемы является использование хука useRef(). Именно это и рекомендует React документация: Они прямо упомянули, что useRef() нужно использовать как аналог this. И более того, для удобства добавили в useRef() возможность передачи начального значения. Поэтому вариант с timeout может выглядеть следующим образом: Возможно в этом решении вас смущает, то что в timeout начинает храниться свойство current, это действительно выглядит немного странно, но у этого есть разумное объяснение, о котором мы рассказывали в предыдущей статье “createRef, setRef, useRef и зачем нужен current в ref”. Использование useRef() для хранения timeout это конечно же очень полезно. Но есть и более интересные способы использования. Например, в компонентах в виде классов есть удобный метод жизненного цикла componentDidUpdate. В качестве первого параметра нам предоставляют prevProps, т.е. props из предыдущей итерации. Это давало нам возможность, сравнивать props из текущей итерации с props из предыдущей. На основании этого выполнять какие-то действия. Если вам кажется, что эту функциональность у вас отняли безвозвратно, тогда вы ошибаетесь. Давайте напишем хук, который будет возвращать props из предыдущей итерации: Здесь мы получаем value из текущей итерации, после создадим ref для хранения данных между итерациями. И в рамках текущей итерации мы вернем текущее значение current равное null. Но перед началом следующей итерации мы обновим current значение, таким образом в следующей итерации в ref у нас будет хранится значение из предыдущей. И осталось только использовать этот хук: В итоге, имея значение counter из предыдущей итерации и из текущей итерации, мы можем покрасить в зеленый цвет, если counter уменьшился, или в красный, если counter увеличился. Мы упомянули лишь несколько базовых вариантов использования ref для решения нетипичных для ref задач. Но их гораздо больше. Например, если вы откроете телеграм десктоп версии, и будете скролить вверх, то у вас будет отображаться дата, а если вниз, она исчезнет. Мы можем хранить предыдущее значение скрола в ref, для того чтобы вычислить в какую же сторону скролит пользователь. Как вы уже догадались, использование ref ограничено лишь вашей фантазией и вы найдете ему гораздо больше вариантов применения, чем мы упомянули в этой статье. И если вы знаете еще какие-то интересные варианты использования ref обязательно пишите в комментариях User