Пошук уроків, статей та іншого контенту
Дізнаєтеся, як useRef зберігає значення між рендерами та дає доступ до DOM-елементів без повторного рендера.
useRefuseRef — це React-хук, який створює об’єкт із властивістю .current:
const ref = useRef(initialValue);Об’єкт повертається повторно під час наступних рендерів того самого компонента. Значення в ref.current:
зберігається між рендерами;
може змінюватися без повторного рендера;
часто використовується для доступу до DOM-елемента;
доступне лише через властивість .current.
На відміну від useState, зміна ref.current сама по собі не оновлює інтерфейс.
Щоб отримати посилання на DOM-елемент, потрібно:
створити ref за допомогою useRef;
передати його елементу через атрибут ref;
звернутися до елемента через ref.current.
import { useRef } from "react";
function SearchForm() {
const inputRef = useRef(null);
function focusInput() {
inputRef.current.focus();
}
return (
<div>
<input ref={inputRef} placeholder="Введіть пошуковий запит" />
<button onClick={focusInput}>Фокус на поле</button>
</div>
);
}
export default SearchForm;Після монтування компонента React запише DOM-елемент у inputRef.current.
Коли компонент ще не змонтований, значенням буде null. Тому звернення до DOM-елемента зазвичай відбувається в обробнику події або після монтування компонента.
Метод .focus() у прикладі є звичайним методом DOM-елемента. React лише надає нам посилання на цей елемент.
useRef також можна використовувати для збереження змінного значення, яке не повинно безпосередньо впливати на інтерфейс.
const clicksRef = useRef(0);
clicksRef.current += 1;Значення clicksRef.current не скидається під час повторного рендера компонента.
Розглянемо повний приклад:
import { useRef, useState } from "react";
function App() {
const inputRef = useRef(null);
const clicksRef = useRef(0);
const [message, setMessage] = useState("Кнопку ще не натискали");
function focusInput() {
inputRef.current?.focus();
}
function handleClick() {
clicksRef.current += 1;
setMessage(
`Кнопку натиснули ${clicksRef.current} ${
clicksRef.current === 1 ? "раз" : "рази"
}`
);
}
return (
<main>
<h1>Приклад useRef</h1>
<input ref={inputRef} placeholder="Введіть текст" />
<div>
<button onClick={focusInput}>Встановити фокус</button>
<button onClick={handleClick}>Збільшити лічильник</button>
</div>
<p>{message}</p>
</main>
);
}
export default App;У цьому прикладі використовуються два refs:
inputRef зберігає посилання на DOM-елемент input;
clicksRef зберігає кількість натискань між рендерами.
Виклик setMessage спричиняє повторний рендер. Під час цього рендера clicksRef.current не втрачає своє значення.
Якби після зміни clicksRef.current не було виклику setMessage, інтерфейс не оновився б. Саме значення ref змінилося б, але React не перемалював би компонент.
useRef і useStateuseRef та useState можуть зберігати значення між рендерами, але поводяться по-різному.
useStateconst [count, setCount] = useState(0);
setCount(count + 1);Після зміни стану React повторно рендерить компонент. Нове значення можна відобразити в JSX.
useRefconst countRef = useRef(0);
countRef.current += 1;Після зміни ref React не запускає повторний рендер. Це підходить для значень, які потрібні логіці компонента, але не повинні самостійно відображатися в інтерфейсі.
Орієнтуйтеся на таке правило:
значення потрібно показати в JSX — використовуйте useState;
потрібно зберегти значення між рендерами без оновлення JSX — використовуйте useRef;
потрібно звернутися до DOM-елемента — використовуйте useRef.
.currentuseRef повертає не саме значення, а об’єкт:
const valueRef = useRef("початкове значення");
console.log(valueRef);
// { current: "початкове значення" }
console.log(valueRef.current);
// "початкове значення"Щоб прочитати або змінити значення, потрібно використовувати .current:
valueRef.current = "нове значення";Не слід переприсвоювати саму змінну ref:
// Неправильно: ref потрібно змінювати через .current
valueRef = "нове значення";Початкове значення передається під час створення ref:
const nameRef = useRef("Анонімний користувач");Під час наступних рендерів React не замінює значення .current на аргумент useRef.
const nameRef = useRef("Перше значення");
nameRef.current = "Змінене значення";Після повторного рендера nameRef.current залишиться "Змінене значення".
Для DOM-посилань зазвичай використовують null:
const buttonRef = useRef(null);До монтування елемента buttonRef.current дорівнює null. Після монтування React встановлює там відповідний DOM-елемент.
useRefНе використовуйте ref для даних, які повинні відображатися в інтерфейсі.
Наприклад, такий код змінить значення, але текст на сторінці не оновиться:
import { useRef } from "react";
function Counter() {
const countRef = useRef(0);
function increment() {
countRef.current += 1;
}
return (
<button onClick={increment}>
Натискань: {countRef.current}
</button>
);
}
export default Counter;Після натискання значення в countRef.current збільшиться, але React не виконає повторний рендер. Тому кнопка продовжить показувати старий текст.
Для такого завдання потрібен стан:
import { useState } from "react";
function Counter() {
const [count, setCount] = useState(0);
function increment() {
setCount((currentCount) => currentCount + 1);
}
return <button onClick={increment}>Натискань: {count}</button>;
}
export default Counter;.currentconst inputRef = useRef(null);
// Неправильно
inputRef.focus();Потрібно звертатися до поточного значення ref:
inputRef.current?.focus();Оператор ?. перевіряє, чи існує елемент. Якщо current дорівнює null, помилки не виникне.
Зміна ref не оновлює JSX:
valueRef.current = "нове значення";Якщо нове значення потрібно одразу показати користувачу, зберігайте його в стані.
На початку ref.current може бути null:
const inputRef = useRef(null);
inputRef.current.focus();Такий код може спричинити помилку. Звертайтеся до ref після монтування, наприклад в обробнику події:
function handleFocus() {
inputRef.current?.focus();
}useRef потрібно викликати безпосередньо в тілі компонента:
function Form() {
const inputRef = useRef(null);
return <input ref={inputRef} />;
}Не створюйте ref усередині обробника події або умовного блоку:
// Неправильно
function Form() {
function handleClick() {
const inputRef = useRef(null);
}
return <button onClick={handleClick}>Натиснути</button>;
}Хуки потрібно викликати на верхньому рівні компонента, щоб React міг правильно зберігати їхній стан між рендерами.
useRef повертає об’єкт із властивістю .current.
Значення ref.current зберігається між рендерами.
Зміна ref.current не спричиняє повторного рендера.
Для доступу до DOM-елемента передайте ref через атрибут ref.
До DOM-елемента звертаються через ref.current.
Для даних, які потрібно показувати в JSX, використовуйте useState, а не useRef.
Для DOM-посилань початковим значенням ref зазвичай є null.