useMap
Описание
useMap — хук, создающий реактивный Map, который вызывает перерисовку компонента при мутациях (set, delete, clear, replaceAll и т.д.). Экземпляр карты стабилен между рендерами; начальные элементы можно передать массивом или ленивой фабрикой.
Сигнатура
ts
function useMap<KeyType = any, ValueType = any>(
initialEntries?:
| ReadonlyArray<[KeyType, ValueType]>
| (() => ReadonlyArray<[KeyType, ValueType]>),
): UseMapReturn<KeyType, ValueType>;Параметры
initialEntries?— начальные пары[key, value]. Поддерживается ленивый вариант: функция, возвращающая массив.
Возвращает
- Реактивную структуру, совместимую с
Map, у которой мутации инициируют перерисовку.
- Реактивную структуру, совместимую с
Примеры
1) Базовое использование: добавление/удаление с перерисовкой
tsx
import { useMap } from '@webeach/react-hooks';
type User = { id: string; name: string };
export function Users() {
const users = useMap<string, User>([
['u1', { id: 'u1', name: 'Alice' }],
['u2', { id: 'u2', name: 'Bob' }],
]);
return (
<div>
<button onClick={() => users.set('u3', { id: 'u3', name: 'Charlie' })}>
Add Charlie
</button>
<button onClick={() => users.delete('u1')}>Remove Alice</button>
<div>Total: {users.size}</div>
<ul>
{users.entries().map(([id, userItem]) => (
<li key={id}>{userItem.name}</li>
))}
</ul>
</div>
);
}2) Полная замена содержимого (replaceAll)
tsx
import { useEffect } from 'react';
import { useMap } from '@webeach/react-hooks';
type CatalogProps = {
fetchAll: () => Promise<Array<[string, Product]>>;
};
export function Catalog(props: CatalogProps) {
const { fetchAll } = props;
const products = useMap<string, Product>();
useEffect(() => {
fetchAll().then((entries) => {
products.replaceAll(entries);
});
}, [fetchAll]);
return <Grid data={products.values()} />;
}3) Изменение вложенных значений
tsx
import { type UseMapReturn } from '@webeach/react-hooks';
type RenameProps = {
users: UseMapReturn<string, { name: string }>;
};
// Важно: мутация объекта по ссылке НЕ вызовет перерисовку.
// Нужно выполнить повторную запись ключа через set.
function Rename(props: RenameProps) {
const { users } = props;
const rename = (id: string, name: string) => {
const current = users.get(id);
if (!current) {
return;
}
users.set(id, { ...current, name }); // триггерит обновление
};
return (
<button onClick={() => rename('u2', 'Bobby')}>Rename Bob → Bobby</button>
);
}Поведение
Реактивность на мутациях
- Вызовы
set,delete,clear,replaceAllинициируют перерисовку компонента.
- Вызовы
Стабильность экземпляра
- Возвращаемый объект сохраняет ссылочную идентичность на протяжении жизни компонента (подходит для пропов/зависимостей).
Ленивая инициализация
- Если передать фабрику
() => entries, начальные данные будут вычислены один раз при первом рендере.
- Если передать фабрику
Чтение без побочных эффектов
- Операции
get,has,values,entriesне вызывают перерисовку; ререндер происходит только после мутаций.
- Операции
Вложенные структуры
- Изменение внутренних полей по ссылке (например,
users.get('u1')!.name = '…') не детектируется. Для обновления UI повторно запишите ключ черезset.
- Изменение внутренних полей по ссылке (например,
Когда использовать
- Коллекции с частыми императивными изменениями: кэш данных, индекс по ключу, хранилище выбранных элементов.
- Когда нужен стабильный Map‑объект, который компоненты могут напрямую мутировать, сохраняя простой API.
- Для UI‑сценариев, где удобен Map (быстрые вставки/удаления/поиск по ключу) и при этом требуется реактивность.
Когда не использовать
- Если достаточно обычного состояния (
useState/useReducer) с иммутабельными обновлениями. - Когда требуется транзакционность/временные версии/история — предусмотрите слой поверх (история изменений), а не разгружайте это на карту.
- Если данные изменяются редко — простая структура (массив/объект) может быть понятнее.
Частые ошибки
Мутация по ссылке без
set- Изменение объекта из карты «на месте» не вызовет перерисовку. Создайте новый объект и вызовите
map.set(key, next).
- Изменение объекта из карты «на месте» не вызовет перерисовку. Создайте новый объект и вызовите
Переинициализация карты
- Не создавайте новый экземпляр вручную внутри рендера. Используйте возвращаемый из
useMapобъект — он стабилен.
- Не создавайте новый экземпляр вручную внутри рендера. Используйте возвращаемый из
Неправильные зависимости эффектов
- Сама ссылка на карту стабильна; добавление её в массив зависимостей не приведёт к перезапуску эффекта при изменении содержимого. Для реакции на изменения читайте производные значения (например,
map.size) и используйте их в зависимостях или обрабатывайте обновления в обработчиках событий.
- Сама ссылка на карту стабильна; добавление её в массив зависимостей не приведёт к перезапуску эффекта при изменении содержимого. Для реакции на изменения читайте производные значения (например,
Типизация
Экспортируемые типы
ExtendedMap<KeyType, ValueType>- Совместим с
Map, но дополнительно предоставляет методreplaceAll(entries)для атомарной пересборки содержимого. - Мутации (
set/delete/clear/replaceAll) инициируют перерисовку компонента.
- Совместим с