← Назад к вопросам

Какие есть Ref в функциональных компонентах?

2.0 Middle🔥 161 комментариев
#JavaScript Core

Комментарии (1)

🐱
deepseek-v3.2PrepBro AI4 апр. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Ref в функциональных компонентах React

В функциональных компонентах React существуют три основных типа ref, каждый из которых решает определённые задачи и имеет свою специфику использования.

1. useRef() - универсальная ссылка

useRef() — это хук, который возвращает изменяемый ref-объект с свойством .current, инициализированным переданным аргументом. Основные сценарии использования:

Хранение DOM-элементов

import { useRef } from 'react';

function TextInput() {
  const inputRef = useRef(null);
  
  const focusInput = () => {
    inputRef.current.focus();
  };
  
  return (
    <div>
      <input ref={inputRef} type="text" />
      <button onClick={focusInput}>Фокус на input</button>
    </div>
  );
}

Сохранение изменяемых значений без триггеринга ререндера

function TimerComponent() {
  const intervalId = useRef(null);
  const [count, setCount] = useState(0);
  
  useEffect(() => {
    intervalId.current = setInterval(() => {
      setCount(prev => prev + 1);
    }, 1000);
    
    return () => clearInterval(intervalId.current);
  }, []);
  
  return <div>Счёт: {count}</div>;
}

2. forwardRef() - передача ref через компоненты

forwardRef() позволяет компонентам принимать ref и передавать их дальше дочерним DOM-элементам или компонентам. Это особенно полезно для библиотек компонентов:

import { forwardRef } from 'react';

const CustomInput = forwardRef((props, ref) => {
  return <input ref={ref} {...props} />;
});

function ParentComponent() {
  const inputRef = useRef(null);
  
  useEffect(() => {
    // Теперь мы имеем доступ к DOM-элементу input
    inputRef.current.focus();
  }, []);
  
  return <CustomInput ref={inputRef} placeholder="Введите текст" />;
}

3. useImperativeHandle() - кастомизация ref

useImperativeHandle() позволяет кастомизировать значение, которое предоставляется через ref при использовании forwardRef. Вместо предоставления полного доступа к DOM-элементу, мы можем предоставить только определённые методы:

import { forwardRef, useRef, useImperativeHandle } from 'react';

const FancyInput = forwardRef((props, ref) => {
  const inputRef = useRef(null);
  
  useImperativeHandle(ref, () => ({
    focus: () => {
      inputRef.current.focus();
    },
    shake: () => {
      // Кастомная анимация
      inputRef.current.style.transform = 'translateX(10px)';
      setTimeout(() => {
        inputRef.current.style.transform = 'translateX(0)';
      }, 100);
    },
    getValue: () => {
      return inputRef.current.value;
    }
  }));
  
  return <input ref={inputRef} {...props} />;
});

function App() {
  const fancyInputRef = useRef(null);
  
  const handleClick = () => {
    fancyInputRef.current.shake(); // Вызываем кастомный метод
    fancyInputRef.current.focus(); // Вызываем стандартный метод
  };
  
  return (
    <div>
      <FancyInput ref={fancyInputRef} />
      <button onClick={handleClick}>Взаимодействие</button>
    </div>
  );
}

Ключевые отличия и рекомендации

  • useRef — основной инструмент для большинства случаев работы с ref
  • forwardRef — необходим для передачи ref через компоненты-обёртки
  • useImperativeHandle — для создания контролируемого API компонента через ref

Важные особенности:

  • Ref не вызывают ререндер компонента при изменении
  • Значение ref сохраняется между рендерами компонента
  • Изменение .current происходит синхронно
  • Ref работают как замыкания в обработчиках событий

Практические паттерны использования:

// Сохранение предыдущего значения
function usePrevious(value) {
  const ref = useRef();
  useEffect(() => {
    ref.current = value;
  });
  return ref.current;
}

// Измерение размеров DOM-элемента
function useElementSize() {
  const ref = useRef(null);
  const [size, setSize] = useState({ width: 0, height: 0 });
  
  useEffect(() => {
    if (ref.current) {
      const updateSize = () => {
        setSize({
          width: ref.current.offsetWidth,
          height: ref.current.offsetHeight
        });
      };
      
      updateSize();
      window.addEventListener('resize', updateSize);
      return () => window.removeEventListener('resize', updateSize);
    }
  }, []);
  
  return [ref, size];
}

Каждый тип ref решает конкретные задачи в функциональных компонентах, обеспечивая гибкость при работе с DOM, сохранении значений и создании reusable-компонентов. Правильное использование ref позволяет создавать эффективные и производительные React-приложения.

Какие есть Ref в функциональных компонентах? | PrepBro