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

Для интеграции Gridstack.js в проект на React используется npm:

npm install gridstack
npm install gridstack-react

gridstack-react предоставляет обёртку для использования Gridstack в React-компонентах. Важно подключить стили библиотеки:

import 'gridstack/dist/gridstack.min.css';
import { GridStack } from 'gridstack';
import { GridStackReact } from 'gridstack-react';

Создание сетки с GridStackReact

GridStackReact позволяет управлять сеткой через свойства компонента. Простейший пример:

import React from 'react';
import { GridStackReact } from 'gridstack-react';
import 'gridstack/dist/gridstack.min.css';

const MyGrid = () => {
  const gridOptions = {
    column: 12,
    float: true,
    cellHeight: 80,
    margin: 5,
    disableOneColumnMode: false
  };

  return (
    <GridStackReact
      className="grid-stack"
      options={gridOptions}
    >
      <div className="grid-stack-item" gs-w="4" gs-h="2" gs-x="0" gs-y="0">
        <div className="grid-stack-item-content">Блок 1</div>
      </div>
      <div className="grid-stack-item" gs-w="4" gs-h="2" gs-x="4" gs-y="0">
        <div className="grid-stack-item-content">Блок 2</div>
      </div>
    </GridStackReact>
  );
};

export default MyGrid;

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

  • gs-w и gs-h — ширина и высота блока в ячейках.
  • gs-x и gs-y — координаты блока в сетке.
  • options — объект настроек, аналогичный конфигурации Gridstack в чистом JS.

Управление сеткой через рефы

Чтобы динамически работать с сеткой (добавлять или удалять элементы, изменять размеры), используется useRef:

import React, { useRef, useEffect } from 'react';
import { GridStack } from 'gridstack';
import 'gridstack/dist/gridstack.min.css';

const DynamicGrid = () => {
  const gridRef = useRef(null);

  useEffect(() => {
    const grid = GridStack.init({ column: 12, float: true }, gridRef.current);

    grid.addWidget(`<div class="grid-stack-item" gs-w="3" gs-h="2">
                      <div class="grid-stack-item-content">Новый блок</div>
                    </div>`);

    return () => grid.destroy();
  }, []);

  return <div className="grid-stack" ref={gridRef}></div>;
};

export default DynamicGrid;

Важные моменты:

  • GridStack.init() создаёт экземпляр сетки для DOM-элемента.
  • addWidget() позволяет добавлять блоки динамически.
  • destroy() корректно удаляет сетку при размонтировании компонента.

Обработка событий

Gridstack поддерживает события, такие как change, dragstart, dragstop, resizestart, resizestop. В React их можно подключить через слушатели после инициализации:

useEffect(() => {
  const grid = GridStack.init({}, gridRef.current);

  grid.on('change', (event, items) => {
    console.log('Сетка изменилась:', items);
  });

  return () => grid.destroy();
}, []);

Особенности событий:

  • Событие change срабатывает после перемещения или изменения размера блоков.
  • items содержит массив объектов с координатами и размерами блоков (x, y, w, h, id).
  • Можно привязать кастомную логику для синхронизации состояния сетки с React state.

Интеграция с React state

Для полной реактивности лучше синхронизировать положение и размеры блоков со стейтом:

const [widgets, setWidgets] = React.useState([
  { id: 1, x: 0, y: 0, w: 4, h: 2, content: 'Блок A' },
  { id: 2, x: 4, y: 0, w: 4, h: 2, content: 'Блок B' }
]);

useEffect(() => {
  const grid = GridStack.init({}, gridRef.current);

  widgets.forEach(widget => {
    grid.addWidget(`<div class="grid-stack-item" gs-x="${widget.x}" gs-y="${widget.y}" gs-w="${widget.w}" gs-h="${widget.h}">
                      <div class="grid-stack-item-content">${widget.content}</div>
                    </div>`);
  });

  grid.on('change', (event, items) => {
    const updatedWidgets = items.map(i => ({
      id: i.id || Math.random(),
      x: i.x,
      y: i.y,
      w: i.w,
      h: i.h,
      content: i.el.textContent
    }));
    setWidgets(updatedWidgets);
  });

  return () => grid.destroy();
}, [widgets]);

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

  • Важно не пересоздавать сетку при каждом рендере, иначе потеряется текущее состояние.
  • Использовать useEffect с пустым массивом зависимостей или с аккуратной логикой сравнения.
  • Структура widgets может быть расширена любыми метаданными для управления содержимым блоков.

Адаптивная сетка и режимы

Gridstack поддерживает адаптивные колонки и мобильный режим:

const gridOptions = {
  column: 12,
  float: true,
  cellHeight: '80px',
  margin: 5,
  disableOneColumnMode: false,
  minRow: 1
};
  • disableOneColumnMode: false позволяет автоматически переводить сетку в один столбец на узких экранах.
  • cellHeight можно задавать числом или строкой с единицами (px).
  • float позволяет блокам плавно перемещаться в свободное пространство.

Кастомизация блоков и стилей

Gridstack использует классы grid-stack-item и grid-stack-item-content. Для изменения внешнего вида можно использовать CSS:

.grid-stack-item-content {
  background-color: #4CAF50;
  color: white;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: 6px;
  font-weight: bold;
  cursor: move;
}

Дополнительно можно применять анимации при перетаскивании или изменении размеров через CSS-переходы.

Динамическое добавление и удаление блоков

Для динамического управления блоками используются методы экземпляра сетки:

const grid = GridStack.init({}, gridRef.current);

// Добавление
grid.addWidget(`<div class="grid-stack-item" gs-w="3" gs-h="2">
                  <div class="grid-stack-item-content">Новый блок</div>
                </div>`);

// Удаление
const item = grid.engine.nodes[0]; // первый блок
grid.removeWidget(item.el);

Замечания:

  • grid.engine.nodes — массив всех блоков с информацией о координатах.
  • Метод removeWidget удаляет блок и обновляет сетку.
  • Динамическая работа с блоками идеально сочетается с React state для синхронизации интерфейса.

Эти подходы позволяют строить гибкую и полностью управляемую сетку в React с использованием Gridstack.js, включая адаптивность, динамическое добавление элементов и реактивное управление состоянием.