MUI (Material-UI) предоставляет мощный набор компонентов для построения интерфейсов, но для повышения повторного использования логики и упрощения работы с состоянием компонентов часто применяются custom hooks. Они позволяют инкапсулировать взаимодействие с MUI-компонентами, обработку событий, управление состояниями и интеграцию с темing-системой.
Частой задачей является управление состоянием компонентов, таких как
Dialog или Drawer. Вместо дублирования логики
открытия/закрытия во множестве компонентов создается hook:
import { useState, useCallback } from 'react';
export function useModal() {
const [isOpen, setIsOpen] = useState(false);
const open = useCallback(() => setIsOpen(true), []);
const close = useCallback(() => setIsOpen(false), []);
const toggle = useCallback(() => setIsOpen(prev => !prev), []);
return { isOpen, open, close, toggle };
}
Применение в компоненте с MUI Dialog:
import { Dialog, DialogTitle, DialogContent, DialogActions, Button } from '@mui/material';
import { useModal } from './hooks/useModal';
function MyDialogComponent() {
const { isOpen, open, close } = useModal();
return (
<>
<Button variant="contained" onCl ick={open}>Открыть диалог</Button>
<Dialog open={isOpen} onCl ose={close}>
<DialogTitle>Пример диалога</DialogTitle>
<DialogContent>Содержимое диалога</DialogContent>
<DialogActions>
<Button onCl ick={close}>Закрыть</Button>
</DialogActions>
</Dialog>
</>
);
}
Ключевая особенность: логика состояния вынесена в hook, что облегчает тестирование и повторное использование.
TextFieldMUI предоставляет контролируемые компоненты ввода
(TextField, Select, Checkbox).
Частая задача — централизованное управление значениями и ошибками формы.
Создание hook для этого упрощает обработку:
import { useState, useCallback } from 'react';
export function useForm(initialValues) {
const [values, setValues] = useState(initialValues);
const [errors, setErrors] = useState({});
const handleChange = useCallback((field) => (event) => {
setValues(prev => ({ ...prev, [field]: event.target.value }));
}, []);
const setError = useCallback((field, message) => {
setErrors(prev => ({ ...prev, [field]: message }));
}, []);
const reset = useCallback(() => {
setValues(initialValues);
setErrors({});
}, [initialValues]);
return { values, errors, handleChange, setError, reset };
}
Применение в компоненте с MUI:
import { TextField, Button } from '@mui/material';
import { useForm } from './hooks/useForm';
function LoginForm() {
const { values, errors, handleChange, setError, reset } = useForm({ email: '', password: '' });
const handleSubmit = () => {
if (!values.email) setError('email', 'Email обязателен');
if (!values.password) setError('password', 'Пароль обязателен');
};
return (
<form>
<TextField
label="Email"
value={values.email}
onCha nge={handleChange('email')}
error={!!errors.email}
helperText={errors.email}
/>
<TextField
label="Пароль"
type="password"
value={values.password}
onCha nge={handleChange('password')}
error={!!errors.password}
helperText={errors.password}
/>
<Button variant="contained" onCl ick={handleSubmit}>Войти</Button>
<Button variant="outlined" onCl ick={reset}>Сбросить</Button>
</form>
);
}
Преимущество: hook изолирует состояние и валидацию, позволяя переиспользовать его для разных форм.
MUI поддерживает тему через ThemeProvider. Custom hook
позволяет менять тему динамически:
import { useState, useMemo, useCallback } from 'react';
import { createTheme } from '@mui/material/styles';
export function useThemeSwitcher() {
const [mode, setMode] = useState('light');
const toggleMode = useCallback(() => {
setMode(prev => (prev === 'light' ? 'dark' : 'light'));
}, []);
const theme = useMemo(() => createTheme({ palette: { mode } }), [mode]);
return { theme, mode, toggleMode };
}
Применение с ThemeProvider:
import { ThemeProvider, Button } from '@mui/material';
import { useThemeSwitcher } from './hooks/useThemeSwitcher';
function App() {
const { theme, toggleMode, mode } = useThemeSwitcher();
return (
<ThemeProvider theme={theme}>
<Button onCl ick={toggleMode}>
Переключить на {mode === 'light' ? 'темную' : 'светлую'} тему
</Button>
{/* Остальные компоненты */}
</ThemeProvider>
);
}
Преимущество: изменения темы становятся простыми, без повторного создания компонентов.
DataGridDataGrid часто требует обработки сортировки, фильтров и
пагинации. Создание hook позволяет инкапсулировать эти состояния:
import { useState, useCallback } from 'react';
export function useDataGrid(initialRows = [], initialPageSize = 10) {
const [rows, setRows] = useState(initialRows);
const [pageSize, setPageSize] = useState(initialPageSize);
const [sortModel, setSortModel] = useState([]);
const [filterModel, setFilterModel] = useState({ items: [] });
return {
rows,
setRows,
pageSize,
setPageSize,
sortModel,
setSortModel,
filterModel,
setFilterModel,
};
}
Применение в компоненте:
import { DataGrid } from '@mui/x-data-grid';
import { useDataGrid } from './hooks/useDataGrid';
function UsersTable({ users }) {
const { rows, setRows, pageSize, setPageSize, sortModel, setSortModel } = useDataGrid(users);
return (
<DataGrid
rows={rows}
columns={[{ field: 'id' }, { field: 'name' }]}
pageSize={pageSize}
onPageSizeCha nge={setPageSize}
sortingOrder={['asc', 'desc']}
sortModel={sortModel}
onSortModelCha nge={setSortModel}
/>
);
}
Результат: логика управления таблицей полностью вынесена в hook, обеспечивая чистоту компонентов.
useTheme,
useMediaQuery, useAutocomplete).useCallback и useMemo для предотвращения
лишних ререндеров.Эти подходы позволяют создавать чистые, масштабируемые и легко тестируемые интерфейсы, где MUI выполняет роль визуального каркаса, а custom hooks инкапсулируют всю логику взаимодействия.