useConst

useConst — вспомогательный хук библиотеки Chakra UI, предназначенный для создания неизменяемого значения, вычисляемого только один раз за жизненный цикл компонента. Хук гарантирует, что значение будет инициализировано при первом рендере и не изменится при последующих перерендерах, даже если компонент обновляется.

Такой подход полезен при работе с:

  • объектами конфигурации
  • массивами данных
  • функциями
  • генерацией уникальных значений
  • созданием инстансов классов
  • тяжелыми вычислениями, которые должны выполняться только один раз

useConst можно рассматривать как упрощённую и более безопасную альтернативу useMemo без зависимостей.


Импорт

import { useConst } from "@chakra-ui/react"

Базовый синтаксис

const value = useConst(initialValue)

или

const value = useConst(() => computeValue())

Параметры

Параметр Тип Описание
initialValue any Значение или функция, возвращающая значение

Если передается функция, она выполняется только один раз.


Основной принцип работы

useConst использует useRef внутри своей реализации. Значение сохраняется в рефе и не пересчитывается при повторных рендерах.

Упрощённая логика работы:

function useConst(init) {
  const ref = React.useRef()

  if (ref.current === undefined) {
    ref.current = typeof init === "function" ? init() : init
  }

  return ref.current
}

Ключевая идея:

  • значение создается один раз
  • затем повторно используется
  • React не вызывает повторную инициализацию

Простейший пример

function Example() {
  const randomId = useConst(() => Math.random())

  return <div>{randomId}</div>
}

При каждом рендере компонента значение randomId остается неизменным.

Без useConst:

function Example() {
  const randomId = Math.random()

  return <div>{randomId}</div>
}

Теперь значение будет меняться при каждом обновлении.


Создание неизменяемого объекта

Распространённый сценарий — создание конфигурационного объекта.

function Chart() {
  const config = useConst({
    width: 400,
    height: 300,
    theme: "dark"
  })

  return <ChartComponent config={config} />
}

Объект создается один раз и не пересоздается при каждом рендере, что уменьшает вероятность лишних перерисовок дочерних компонентов.


Использование функции-инициализатора

Если вычисление значения затратное, используется функция:

function Example() {
  const data = useConst(() => {
    return generateLargeDataset()
  })

  return <DataViewer data={data} />
}

generateLargeDataset() выполняется только один раз.


Генерация уникальных идентификаторов

useConst удобен для генерации стабильных идентификаторов.

function InputField() {
  const id = useConst(() => `input-${Math.random().toString(36).slice(2)}`)

  return (
    <>
      <label htmlFor={id}>Name</label>
      <input id={id} />
    </>
  )
}

Идентификатор остается постоянным независимо от количества перерисовок.


Создание экземпляров классов

Иногда компоненту требуется один постоянный экземпляр объекта.

function WebSocketComponent() {
  const socket = useConst(() => new WebSocket("wss://example.com"))

  return <Connection socket={socket} />
}

Без useConst новый WebSocket создавался бы при каждом рендере.


Использование с массивами

Массивы часто используются как константные структуры данных.

function Menu() {
  const items = useConst([
    { id: 1, label: "Home" },
    { id: 2, label: "Profile" },
    { id: 3, label: "Settings" }
  ])

  return (
    <ul>
      {items.map(item => (
        <li key={item.id}>{item.label}</li>
      ))}
    </ul>
  )
}

Массив не будет пересоздаваться при обновлениях состояния.


Сравнение с useMemo

Хук Когда используется Пересчет
useMemo мемоизация вычислений при изменении зависимостей
useConst значение должно существовать один раз никогда

Пример useMemo:

const value = useMemo(() => compute(), [deps])

Пример useConst:

const value = useConst(() => compute())

Разница:

  • useMemo зависит от массива зависимостей
  • useConst игнорирует любые зависимости

Сравнение с useRef

useConst фактически является удобной оберткой над useRef.

Использование useRef

function Example() {
  const ref = useRef(null)

  if (ref.current === null) {
    ref.current = createValue()
  }

  return ref.current
}

Использование useConst

function Example() {
  const value = useConst(() => createValue())

  return value
}

useConst делает код:

  • короче
  • чище
  • безопаснее

Предотвращение лишних рендеров

Если объект создается внутри компонента, React будет считать его новым при каждом рендере.

Проблемный код:

function Parent() {
  const config = {
    animation: true
  }

  return <Child config={config} />
}

Компонент Child будет получать новую ссылку на объект каждый раз.

Решение:

function Parent() {
  const config = useConst({
    animation: true
  })

  return <Child config={config} />
}

Теперь ссылка стабильна.


Использование с функциями

useConst может хранить функцию.

function Component() {
  const logger = useConst(() => {
    return message => console.log(message)
  })

  logger("Hello")
}

Функция создается только один раз.


Сложная инициализация

Иногда значение требует много шагов для создания.

function Editor() {
  const editor = useConst(() => {
    const instance = new EditorEngine()

    instance.enableHistory()
    instance.setTheme("dark")

    return instance
  })

  return <EditorView editor={editor} />
}

Инициализация выполняется только при первом рендере.


Когда использовать useConst

Наиболее типичные сценарии:

1. Конфигурационные объекты

const options = useConst({
  animation: true,
  duration: 300
})

2. Большие наборы данных

const dataset = useConst(() => buildDataset())

3. Сервисы или менеджеры

const store = useConst(() => new Store())

4. Генерация уникальных значений

const uuid = useConst(generateUUID)

5. Создание референсных значений

const defaultState = useConst({
  loading: false,
  error: null
})

Ограничения

Значение не обновляется

После инициализации изменить значение невозможно.

const value = useConst(10)

value всегда будет равен 10.


Не подходит для реактивных данных

Если значение должно зависеть от пропсов или состояния, следует использовать useMemo.

Неправильный пример:

const value = useConst(() => props.count * 2)

props.count может изменяться, но значение пересчитано не будет.

Правильный вариант:

const value = useMemo(() => props.count * 2, [props.count])

Не используется для состояния

useConst не заменяет useState.

const value = useConst(10)

Это неизменяемая константа, а не состояние.


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

Использование функции для тяжелых вычислений

const data = useConst(() => expensiveComputation())

Использование для стабильных ссылок

const handlers = useConst({
  onOpen: () => setOpen(true),
  onClose: () => setOpen(false)
})

Использование для сторонних библиотек

const chart = useConst(() => new ChartJS(ctx, config))

Минимизация логики внутри компонента

const constants = useConst({
  maxItems: 20,
  pageSize: 10
})

Внутренняя роль в Chakra UI

В Chakra UI useConst применяется для:

  • хранения конфигураций компонентов
  • генерации стабильных id
  • оптимизации производительности
  • создания неизменяемых структур данных

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


Краткая схема использования

Если значение должно:

Требование Решение
изменяться useState
пересчитываться при изменении зависимостей useMemo
существовать один раз useConst
хранить изменяемое значение без рендера useRef

Пример полноценного компонента

import { useConst, Box, Button } from "@chakra-ui/react"

function Counter() {
  const initialData = useConst(() => ({
    start: 10,
    step: 2
  }))

  const [count, setCount] = React.useState(initialData.start)

  return (
    <Box>
      <Box>{count}</Box>

      <Button onCl ick={() => setCount(c => c + initialData.step)}>
        Increment
      </Button>
    </Box>
  )
}

initialData создается только один раз и используется на протяжении всего жизненного цикла компонента.