Чем отличаются useRef и createRef?

👨‍💻 Frontend Developer 🟠 Может встретиться 🎚️ Средний
#React #Hooks

Краткий ответ

useRef и createRef — это два способа создания ссылок в React с разными областями применения:

  1. useRef — хук для функциональных компонентов 🎣
  2. createRef — метод для классовых компонентов 🏗️
  3. Время жизни — useRef сохраняется между рендерами ♻️
  4. Производительность — useRef более оптимизирован 🚀
  5. Использование — useRef в функциях, createRef в классах 📍
// useRef в функциональном компоненте
const inputRef = useRef(null);
 
// createRef в классовом компоненте
this.inputRef = createRef();

Полный ответ

useRef и createRef — это инструменты для работы с DOM-элементами и хранения мутабельных значений в React! Они решают похожие задачи, но работают по-разному. 🔧

Основные различия

ХарактеристикаuseRefcreateRef
Тип компонентаФункциональныйКлассовый
Время жизниСохраняется между рендерамиСоздаётся заново каждый раз
ПроизводительностьВысокаяНиже
СовременностьСовременный подходУстаревший подход

1. useRef — для функциональных компонентов

useRef создаёт мутабельный объект, который сохраняется между рендерами:

import { useRef, useEffect } from 'react';
 
function MyComponent() {
  const inputRef = useRef(null);
  const countRef = useRef(0);
 
  useEffect(() => {
    // Фокус на input
    inputRef.current.focus();
  }, []);
 
  const handleClick = () => {
    countRef.current += 1;
    console.log(countRef.current); // Не вызывает ререндер
  };
 
  return (
    <div>
      <input ref={inputRef} />
      <button onClick={handleClick}>Увеличить счётчик</button>
    </div>
  );
}

2. createRef — для классовых компонентов

createRef создаёт новый объект ссылки при каждом вызове:

import React, { Component, createRef } from 'react';
 
class MyComponent extends Component {
  constructor(props) {
    super(props);
    this.inputRef = createRef();
    this.countRef = createRef();
  }
 
  componentDidMount() {
    // Фокус на input
    this.inputRef.current.focus();
  }
 
  handleClick = () => {
    console.log(this.inputRef.current.value);
  };
 
  render() {
    return (
      <div>
        <input ref={this.inputRef} />
        <button onClick={this.handleClick}>Получить значение</button>
      </div>
    );
  }
}

3. Время жизни и производительность

useRef — оптимизированный

function Component() {
  const ref = useRef(null); // Создаётся один раз
  
  // ref.current всегда один и тот же объект
  console.log(ref); // { current: null }
  
  return <div ref={ref} />;
}

createRef — создаётся заново

class Component extends React.Component {
  render() {
    const ref = createRef(); // Создаётся при каждом рендере!
    
    return <div ref={ref} />;
  }
}
 
// Правильное использование в классе
class Component extends React.Component {
  constructor(props) {
    super(props);
    this.ref = createRef(); // Создаётся один раз
  }
  
  render() {
    return <div ref={this.ref} />;
  }
}

4. Практические примеры

Доступ к DOM-элементу

// useRef
function ScrollToTop() {
  const topRef = useRef(null);
  
  const scrollToTop = () => {
    topRef.current?.scrollIntoView({ behavior: 'smooth' });
  };
  
  return (
    <div>
      <div ref={topRef}>Верх страницы</div>
      <button onClick={scrollToTop}>Наверх</button>
    </div>
  );
}
 
// createRef
class ScrollToTop extends Component {
  constructor(props) {
    super(props);
    this.topRef = createRef();
  }
  
  scrollToTop = () => {
    this.topRef.current?.scrollIntoView({ behavior: 'smooth' });
  };
  
  render() {
    return (
      <div>
        <div ref={this.topRef}>Верх страницы</div>
        <button onClick={this.scrollToTop}>Наверх</button>
      </div>
    );
  }
}

Хранение мутабельных значений

// useRef для хранения значений без ререндера
function Timer() {
  const [time, setTime] = useState(0);
  const intervalRef = useRef(null);
  
  const startTimer = () => {
    intervalRef.current = setInterval(() => {
      setTime(prev => prev + 1);
    }, 1000);
  };
  
  const stopTimer = () => {
    clearInterval(intervalRef.current);
  };
  
  return (
    <div>
      <p>Время: {time}</p>
      <button onClick={startTimer}>Старт</button>
      <button onClick={stopTimer}>Стоп</button>
    </div>
  );
}

5. Когда использовать каждый

useRef используйте когда:

  • ✅ Работаете с функциональными компонентами
  • ✅ Нужен доступ к DOM-элементам
  • ✅ Храните мутабельные значения
  • ✅ Работаете с таймерами/интервалами

createRef используйте когда:

  • ✅ Работаете с классовыми компонентами
  • ✅ Поддерживаете legacy код
  • ✅ Нужна совместимость со старыми версиями React

Лучшие практики

  1. Предпочитайте useRef в современных приложениях 🎯
  2. Инициализируйте в constructor для createRef 🏗️
  3. Проверяйте на null перед использованием ✅
  4. Не используйте для состояния — только для мутабельных значений 🚫

Частые ошибки

Неправильно:

// createRef в render - создаётся заново!
class Component extends React.Component {
  render() {
    const ref = createRef();
    return <div ref={ref} />;
  }
}

Правильно:

// createRef в constructor
class Component extends React.Component {
  constructor(props) {
    super(props);
    this.ref = createRef();
  }
  
  render() {
    return <div ref={this.ref} />;
  }
}

Заключение

Основные различия useRef и createRef:

  • useRef — современный хук для функциональных компонентов
  • createRef — классический метод для классовых компонентов
  • Производительность — useRef более оптимизирован
  • Время жизни — useRef сохраняется, createRef пересоздаётся

Используйте useRef в современной разработке! 🚀