useRef() похож на useSate(), поскольку он позволяет нам сохранять (оставлять неизменными) значения между рендерингами, но, в отличие от useState(), хук Ref не вызывает повторный рендеринг, когда изменяемое значение изменено.

useRef() возвращает изменяемый объект, текущее свойство которого установлено с начальным значением, которое передается в качестве аргумента функции Ref.

const refObject = useRef(initial_value);

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

Есть два основных варианта использования useRef():

  1. Чтобы создать постоянные изменяемые переменные (они называются ссылками или ссылками).
  2. Чтобы получить доступ к элементам DOM (или элементам React).

Давайте углубимся в это.

1. useRef() для создания постоянных изменяемых переменных.

Попытка подсчитать количество повторных рендеров компонента с использованием useState приведет к бесконечному циклу, поскольку сам useState вызывает повторный рендеринг. Это продемонстрировано в примере ниже.

import React,{useState, useEffect} from 'react'

function App() {

  const [text, setText] = useState('')
  const [count, setCount] = useState(0)

  useEffect(() => {
    setCount(prevStateCount => prevStateCount + 1)
  })

  return (
    <div>
      <input value={text} onChange={e=>setText(e.target.value)} />
      <div>Type some text in the box</div>
      <div>Component rendered {count} times</div>
    </div>
  )
}

export default App

Во время начального рендеринга компонента «счетчик» увеличивается, что приводит к повторному рендерингу компонента, и, следовательно, счетчик снова увеличивается, что приводит к повторному рендерингу компонента. По сути, это бесконечный цикл увеличения «счетчика» и повторного рендеринга компонентов.

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

import React,{useState, useEffect, useRef} from 'react'

function App() {

  const [text, setText] = useState('')
  const count = useRef(1)

  useEffect(() => {
    count.current = count.current + 1
  })

  return (
    <div>
      <input value={text} onChange={e=>setText(e.target.value)} />
      <div>Type some text in the box</div>
      <div>Component rendered {count.current} times</div>
    </div>
  )
}

export default App

useRef() заменяет useState(), а count — это объект со свойством current. Свойство current сохраняется при обновлении между различными рендерингами.

На изображении ниже мы можем наблюдать, что каждый раз, когда в поле ввода вводится символ, счетчик увеличивается. Поскольку введено слово «яблоко», счетчик увеличивается 6 раз (1 при начальном рендеринге + увеличение на 1 для каждого символа). Независимо от того, сколько раз изменяется счетчик, наш компонент не подвергается повторному рендерингу, поскольку он отделен от цикла рендеринга нашего компонента.

2. Доступ к элементам DOM

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

Каждый элемент HTML имеет атрибут ref. Мы можем добавить атрибут ref к элементу, чтобы получить доступ к элементу непосредственно в DOM.

Давайте разберем этот вариант использования на примере. Рассмотрим код для сценария, в котором мы хотим сосредоточиться на вводе при нажатии кнопки.

import React,{useRef} from 'react'

function App() {

  const inputRef = useRef()

  const focus = () => {
    inputRef.current.focus()
  }
  return (
    <div>
      <input ref={inputRef} />
      <button onClick={focus}>Click to focus</button>
    </div>
  )
}

export default App

Каждый раз, когда inputRef отображается на экране, переменная inputRef устанавливается в элемент input. Поэтому в функции focus мы обращаемся к текущему свойству переменной inputRef (это соответствует элементу input), а затем фокусируемся на нем.

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

Еще один лайфхак с useRef() 💡 →
Представьте себе обновление состояния для каждого символа при работе с формами. Это может быть немного чрезмерным. Используя Refs, мы можем установить соединение между HTML-элементом, который в конечном итоге отображается, и другим кодом JavaScript.

👏 Поздравляем и отличного настроения 👏. Вы рассмотрели три хука React. Это было бы хорошим моментом, чтобы заново собрать свое понимание этих крючков.

Если вы чувствуете себя уверенно 😎, погрузитесь прямо в useReducer().