Какие знаешь паттерны переиспользования кода в React?
Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
Паттерны переиспользования кода в React
В React существует несколько фундаментальных паттернов для переиспользования кода, которые эволюционировали вместе с развитием библиотеки. Эти подходы позволяют создавать более поддерживаемые, тестируемые и масштабируемые приложения.
1. Компонентный подход (Component Composition)
Базовый принцип React — композиция компонентов. Вместо создания монолитных компонентов, мы разбиваем интерфейс на мелкие переиспользуемые части.
// Базовый переиспользуемый компонент кнопки
const Button = ({ children, variant = 'primary', onClick }) => {
const baseClasses = 'px-4 py-2 rounded font-medium';
const variants = {
primary: 'bg-blue-600 text-white hover:bg-blue-700',
secondary: 'bg-gray-200 text-gray-800 hover:bg-gray-300',
danger: 'bg-red-600 text-white hover:bg-red-700'
};
return (
<button
className={`${baseClasses} ${variants[variant]}`}
onClick={onClick}
>
{children}
</button>
);
};
// Использование
const App = () => (
<div>
<Button variant="primary">Сохранить</Button>
<Button variant="secondary">Отмена</Button>
</div>
);
2. Higher-Order Components (HOC)
HOC — это функция, которая принимает компонент и возвращает новый компонент с дополнительной функциональностью. Этот паттерн был особенно популярен до появления хуков.
// HOC для добавления логики аутентификации
const withAuth = (WrappedComponent) => {
const AuthenticatedComponent = (props) => {
const [isAuthenticated, setIsAuthenticated] = useState(false);
useEffect(() => {
// Проверка аутентификации
checkAuth().then(setIsAuthenticated);
}, []);
if (!isAuthenticated) {
return <div>Пожалуйста, войдите в систему</div>;
}
return <WrappedComponent {...props} />;
};
// Для отладки в DevTools
AuthenticatedComponent.displayName = `WithAuth(${WrappedComponent.displayName || WrappedComponent.name})`;
return AuthenticatedComponent;
};
// Использование
const UserProfile = ({ user }) => <div>Профиль: {user.name}</div>;
const ProtectedUserProfile = withAuth(UserProfile);
3. Render Props
Паттерн Render Props предполагает передачу функции в качестве пропса, которая возвращает React-элемент. Это позволяет компонентам делиться своей внутренней логикой.
// Компонент с render prop для отслеживания мыши
class MouseTracker extends React.Component {
state = { x: 0, y: 0 };
handleMouseMove = (event) => {
this.setState({
x: event.clientX,
y: event.clientY
});
};
render() {
return (
<div onMouseMove={this.handleMouseMove}>
{this.props.render(this.state)}
</div>
);
}
}
// Использование
const App = () => (
<MouseTracker render={({ x, y }) => (
<div>
Координаты мыши: {x}, {y}
</div>
)} />
);
4. Кастомные хуки (Custom Hooks)
С появлением хуков в React 16.8, кастомные хуки стали предпочтительным способом переиспользования логики с состоянием. Они позволяют извлекать и повторно использовать логику состояния между компонентами.
// Кастомный хук для работы с localStorage
const useLocalStorage = (key, initialValue) => {
const [storedValue, setStoredValue] = useState(() => {
try {
const item = window.localStorage.getItem(key);
return item ? JSON.parse(item) : initialValue;
} catch (error) {
console.error(error);
return initialValue;
}
});
const setValue = (value) => {
try {
const valueToStore = value instanceof Function ? value(storedValue) : value;
setStoredValue(valueToStore);
window.localStorage.setItem(key, JSON.stringify(valueToStore));
} catch (error) {
console.error(error);
}
};
return [storedValue, setValue];
};
// Использование в разных компонентах
const ThemeToggle = () => {
const [theme, setTheme] = useLocalStorage('theme', 'light');
const toggleTheme = () => {
setTheme(prev => prev === 'light' ? 'dark' : 'light');
};
return (
<button onClick={toggleTheme}>
Переключить тему: {theme}
</button>
);
};
5. Компоненты-провайдеры (Provider Pattern)
Используется в связке с Context API для передачи данных через дерево компонентов без явной передачи пропсов на каждом уровне.
// Создание контекста
const ThemeContext = React.createContext();
// Провайдер
const ThemeProvider = ({ children }) => {
const [theme, setTheme] = useState('light');
const toggleTheme = () => {
setTheme(prev => prev === 'light' ? 'dark' : 'light');
};
return (
<ThemeContext.Provider value={{ theme, toggleTheme }}>
{children}
</ThemeContext.Provider>
);
};
// Кастомный хук для использования контекста
const useTheme = () => {
const context = useContext(ThemeContext);
if (!context) {
throw new Error('useTheme должен использоваться внутри ThemeProvider');
}
return context;
};
6. Компоненты как дети (Children Pattern)
Использование props.children или именованных слотов для создания гибких компонентов-контейнеров.
// Карточка с заголовком и контентом
const Card = ({ title, children, footer }) => (
<div className="card">
{title && <div className="card-header">{title}</div>}
<div className="card-body">{children}</div>
{footer && <div className="card-footer">{footer}</div>}
</div>
);
// Использование
const UserCard = ({ user }) => (
<Card
title={user.name}
footer={<button>Редактировать</button>}
>
<p>Email: {user.email}</p>
<p>Роль: {user.role}</p>
</Card>
);
Критерии выбора паттерна
При выборе паттерна для переиспользования кода следует учитывать:
- Сложность логики: Для простой логики — компоненты, для сложной — кастомные хуки
- Необходимость в состоянии: HOC и render props для классовых компонентов, кастомные хуки — для функциональных
- Гибкость vs простота: Render props предлагают больше гибкости, HOC — более простой API
- Производительность: Context API может вызывать лишние ререндеры, что требует оптимизации
- Типизация: Каждый паттерн имеет свои особенности при работе с TypeScript
Современные тенденции
В современной экосистеме React наблюдается смещение в сторону:
- Кастомных хуков как основного способа переиспользования логики
- Компонентной композиции через children и slots
- Библиотек состояний (Zustand, Jotai) для сложных сценариев
- Server Components для разделения клиентской и серверной логики
Каждый паттерн имеет свои сильные стороны и оптимальные сценарии применения. Ключ к эффективному переиспользованию кода — понимание, когда какой подход использовать, и комбинирование паттернов для решения конкретных задач.