Drawer с роутингом

Основы компонента Drawer

Drawer в библиотеке MUI представляет собой боковую панель, которая может выезжать слева, справа, сверху или снизу экрана. Основная цель Drawer — предоставить пользователю навигационное меню или дополнительные элементы управления, которые не занимают постоянное место на экране. В MUI Drawer реализован как контролируемый компонент: его открытие и закрытие управляется через проп open и событие onClose.

Пример базового использования:

import React, { useState } from 'react';
import Drawer from '@mui/material/Drawer';
import Button from '@mui/material/Button';
import List from '@mui/material/List';
import ListItem from '@mui/material/ListItem';
import ListItemText from '@mui/material/ListItemText';

function BasicDrawer() {
  const [open, setOpen] = useState(false);

  return (
    <>
      <Button onCl ick={() => setOpen(true)}>Открыть меню</Button>
      <Drawer anchor="left" open={open} onCl ose={() => setOpen(false)}>
        <List>
          <ListItem button>
            <ListItemText primary="Главная" />
          </ListItem>
          <ListItem button>
            <ListItemText primary="Профиль" />
          </ListItem>
        </List>
      </Drawer>
    </>
  );
}

Здесь anchor=“left” определяет сторону, с которой Drawer выезжает.


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

Для организации навигации внутри приложения Drawer часто комбинируют с React Router. Каждое меню в Drawer становится ссылкой на отдельный маршрут, что позволяет менять содержимое основного экрана без перезагрузки страницы.

Использование Link из react-router-dom в списке Drawer:

import { Link } from 'react-router-dom';

<List>
  <ListItem button component={Link} to="/">
    <ListItemText primary="Главная" />
  </ListItem>
  <ListItem button component={Link} to="/profile">
    <ListItemText primary="Профиль" />
  </ListItem>
  <ListItem button component={Link} to="/settings">
    <ListItemText primary="Настройки" />
  </ListItem>
</List>

Проп component={Link} позволяет элементу MUI ListItem вести себя как React Router Link, сохраняя стили Material UI и обеспечивая корректную маршрутизацию.


Управление состоянием Drawer при навигации

В приложениях с Drawer важно закрывать панель после выбора пункта меню на мобильных устройствах. Это можно реализовать через колбэк, который вызывается при клике на элемент списка:

function handleDrawerClose() {
  setOpen(false);
}

<List>
  <ListItem button component={Link} to="/" onCl ick={handleDrawerClose}>
    <ListItemText primary="Главная" />
  </ListItem>
  <ListItem button component={Link} to="/profile" onCl ick={handleDrawerClose}>
    <ListItemText primary="Профиль" />
  </ListItem>
</List>

Такой подход обеспечивает плавный пользовательский опыт, особенно на маленьких экранах.


Стилизация Drawer и List

MUI позволяет кастомизировать внешний вид Drawer через sx или стилизованные компоненты. Пример с фиксированной шириной и тёмным фоном:

<Drawer
  anchor="left"
  open={open}
  onCl ose={() => setOpen(false)}
  sx={{
    '& .MuiDrawer-paper': {
      width: 240,
      backgroundColor: '#1e1e1e',
      color: '#fff',
    },
  }}
>
  <List>
    <ListItem button component={Link} to="/">
      <ListItemText primary="Главная" />
    </ListItem>
    <ListItem button component={Link} to="/profile">
      <ListItemText primary="Профиль" />
    </ListItem>
  </List>
</Drawer>

С помощью & .MuiDrawer-paper можно напрямую влиять на внутренний контейнер Drawer.


Drawer с динамическими маршрутами

Для приложений с большим количеством маршрутов удобно хранить конфигурацию в массиве и рендерить меню через map:

const menuItems = [
  { text: 'Главная', path: '/' },
  { text: 'Профиль', path: '/profile' },
  { text: 'Настройки', path: '/settings' },
];

<List>
  {menuItems.map(item => (
    <ListItem
      button
      key={item.text}
      component={Link}
      to={item.path}
      onCl ick={() => setOpen(false)}
    >
      <ListItemText primary={item.text} />
    </ListItem>
  ))}
</List>

Такой подход упрощает поддержку и добавление новых пунктов меню без дублирования кода.


Persistent и Mini variant Drawer

MUI предоставляет варианты Drawer:

  • Temporary — стандартный Drawer, выезжает и закрывается по событию, как в мобильной навигации.
  • Persistent — Drawer остаётся видимым, но может быть скрыт пользователем, при этом контент смещается.
  • Mini variant — Drawer сворачивается в узкую полоску, оставляя иконки, полезно для десктопных приложений.

Пример Persistent Drawer:

<Drawer
  variant="persistent"
  anchor="left"
  open={open}
  sx={{
    width: 240,
    flexShrink: 0,
    '& .MuiDrawer-paper': { width: 240 },
  }}
>
  <List>
    {menuItems.map(item => (
      <ListItem
        button
        key={item.text}
        component={Link}
        to={item.path}
      >
        <ListItemText primary={item.text} />
      </ListItem>
    ))}
  </List>
</Drawer>

Активный маршрут и подсветка выбранного пункта

Для визуальной подсветки текущего маршрута используют хук useLocation из React Router:

import { useLocation } from 'react-router-dom';

const location = useLocation();

<List>
  {menuItems.map(item => (
    <ListItem
      button
      key={item.text}
      component={Link}
      to={item.path}
      selected={location.pathname === item.path}
      onCl ick={() => setOpen(false)}
    >
      <ListItemText primary={item.text} />
    </ListItem>
  ))}
</List>

Проп selected автоматически применяет MUI стили для активного элемента, улучшая UX.


Drawer с вложенными списками

Для меню с подкатегориями используют компонент Collapse вместе с List:

import Collapse from '@mui/material/Collapse';
import ExpandLess from '@mui/icons-material/ExpandLess';
import ExpandMore from '@mui/icons-material/ExpandMore';

const [openSubMenu, setOpenSubMenu] = useState(false);

<ListItem button onCl ick={() => setOpenSubMenu(!openSubMenu)}>
  <ListItemText primary="Настройки" />
  {openSubMenu ? <ExpandLess /> : <ExpandMore />}
</ListItem>
<Collapse in={openSubMenu} timeout="auto" unmountOnExit>
  <List component="div" disablePadding>
    <ListItem button component={Link} to="/settings/profile">
      <ListItemText primary="Профиль" />
    </ListItem>
    <ListItem button component={Link} to="/settings/account">
      <ListItemText primary="Аккаунт" />
    </ListItem>
  </List>
</Collapse>

Использование Collapse позволяет создавать многоуровневое меню с анимацией и сохранением стиля MUI.


Итоговая структура Drawer с роутингом

  • Drawer: контейнер боковой панели.
  • List + ListItem: пункты меню с маршрутизацией.
  • Link + component={Link}: интеграция с React Router.
  • useLocation + selected: подсветка текущего маршрута.
  • Collapse: вложенные подменю.
  • sx или styled: стилизация панели и элементов.

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