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

Библиотека Muuri предоставляет мощный инструмент для организации динамических сеток с возможностью перетаскивания, фильтрации и анимации элементов. В контексте React важно учитывать особенности работы с виртуальным DOM, чтобы интеграция была эффективной и корректной.

Для начала необходимо установить библиотеку:

npm install muuri

или через Yarn:

yarn add muuri

Импорт в компонент React выглядит следующим образом:

import Muuri from 'muuri';
import { useEffect, useRef } from 'react';

Основной подход заключается в использовании useRef для получения ссылки на контейнер сетки и useEffect для инициализации Muuri после рендера.


Инициализация сетки

Создание сетки выполняется в useEffect, чтобы гарантировать наличие DOM-элементов:

const gridRef = useRef(null);
const muuriInstance = useRef(null);

useEffect(() => {
  if (gridRef.current) {
    muuriInstance.current = new Muuri(gridRef.current, {
      dragEnabled: true,
      layout: {
        rounding: false
      }
    });
  }

  return () => {
    if (muuriInstance.current) {
      muuriInstance.current.destroy();
    }
  };
}, []);

Ключевые моменты:

  • gridRef обеспечивает доступ к DOM-контейнеру сетки.
  • muuriInstance хранит ссылку на объект Muuri для дальнейших операций, таких как фильтрация или сортировка.
  • Функция очистки в return уничтожает экземпляр сетки при размонтировании компонента, предотвращая утечки памяти.

Добавление и удаление элементов

В React элементы часто управляются через состояние. Для синхронизации с Muuri необходимо использовать методы add и remove экземпляра сетки.

const [items, setItems] = useState([1, 2, 3]);

useEffect(() => {
  if (muuriInstance.current) {
    muuriInstance.current.add(items.map(item => {
      const element = document.createElement('div');
      element.className = 'item';
      element.textContent = `Элемент ${item}`;
      return element;
    }));
  }
}, [items]);

Удаление элементов производится с помощью метода remove:

const removeItem = (index) => {
  if (muuriInstance.current) {
    const itemToRemove = muuriInstance.current.getItems()[index];
    muuriInstance.current.remove(itemToRemove, { removeElements: true });
    setItems(prev => prev.filter((_, i) => i !== index));
  }
};

Особенности интеграции с React:

  • В React элементы создаются через JSX, но Muuri требует реальных DOM-элементов. Для динамических операций часто используется document.createElement или cloneNode.
  • При обновлении состояния важно синхронизировать изменения с Muuri, иначе сетка перестанет соответствовать UI.

Сортировка и фильтрация элементов

Muuri предоставляет удобные методы для сортировки и фильтрации:

// Фильтрация по чётным элементам
muuriInstance.current.filter(item => {
  const value = parseInt(item.getElement().textContent.replace(/\D/g, ''), 10);
  return value % 2 === 0;
});

// Сортировка по возрастанию
muuriInstance.current.sort((a, b) => {
  const aValue = parseInt(a.getElement().textContent.replace(/\D/g, ''), 10);
  const bValue = parseInt(b.getElement().textContent.replace(/\D/g, ''), 10);
  return aValue - bValue;
});

Важно:

  • Методы filter и sort автоматически запускают анимацию, если она включена в настройках сетки.
  • Фильтрация скрывает элементы, но не удаляет их из DOM, что позволяет динамически возвращать их без перерисовки всего компонента.

Перетаскивание элементов в React

Drag-and-drop в Muuri работает независимо от React, но для корректного взаимодействия с состоянием рекомендуется отслеживать события Muuri:

useEffect(() => {
  if (!muuriInstance.current) return;

  const grid = muuriInstance.current;

  grid.on('move', () => {
    const newOrder = grid.getItems().map(item =>
      parseInt(item.getElement().textContent.replace(/\D/g, ''), 10)
    );
    setItems(newOrder);
  });

  return () => grid.off('move');
}, []);

Ключевые моменты:

  • Событие move позволяет обновлять React-состояние при изменении порядка элементов.
  • Без синхронизации состояние React и визуальная сетка могут расходиться, что приведёт к неожиданному поведению при перерендере.

Настройка анимации и производительности

Muuri поддерживает плавные анимации при перемещении элементов, изменение их размеров и фильтрацию. В React важно отключать лишние перерендеры:

muuriInstance.current = new Muuri(gridRef.current, {
  dragEnabled: true,
  layout: {
    fillGaps: true,
    rounding: false,
    horizontal: false
  },
  layoutOnInit: true,
  dragContainer: document.body
});

Рекомендации для производительности:

  • Избегать использования JSX для каждого элемента сетки, если требуется динамическое добавление большого числа элементов.
  • Для сложных операций использовать requestAnimationFrame совместно с Muuri.
  • Минимизировать количество перерендеров компонентов при изменении состояния, синхронизируя изменения напрямую с экземпляром Muuri.

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

  • В функциональных компонентах предпочтительно использовать useRef и useEffect.
  • В классовых компонентах Muuri инициализируется в componentDidMount, а уничтожается в componentWillUnmount. Пример:
componentDidMount() {
  this.grid = new Muuri(this.gridRef, { dragEnabled: true });
}

componentWillUnmount() {
  this.grid.destroy();
}

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


Эта интеграция позволяет создавать высоко динамические, интерактивные сетки в React с полным контролем над анимацией, сортировкой и перетаскиванием элементов, используя преимущества Muuri без нарушения принципов виртуального DOM.