React Router предоставляет возможность создавать вложенные маршруты,
которые позволяют компонентам рендериться внутри других компонентов. Для
эффективного управления данными между родительскими и дочерними
маршрутами используется компонент Outlet.
Он служит маркером, куда будет вставлен дочерний маршрут в структуре
маршрутизации. Одной из ключевых возможностей является передача
контекста через Outlet, что позволяет дочерним компонентам
получать данные от родителя без необходимости использовать глобальное
состояние или пропсы через несколько уровней.
Компонент Outlet используется в
родительском маршруте:
import { Outlet } from 'react-router-dom';
function Dashboard() {
return (
<div>
<h1>Панель управления</h1>
<Outlet />
</div>
);
}
В этом примере Outlet будет заменён
компонентом дочернего маршрута в момент навигации. Если требуется
передать данные от Dashboard к дочерним компонентам, можно
воспользоваться context пропом:
<Outlet context={{ user: currentUser, permissions: userPermissions }} />
Теперь дочерние компоненты смогут получить доступ к этому контексту
через хук useOutletContext.
Хук useOutletContext предоставляет
доступ к объекту контекста, переданному через Outlet. Его
можно использовать следующим образом:
import { useOutletContext } from 'react-router-dom';
function UserSettings() {
const { user, permissions } = useOutletContext();
return (
<div>
<h2>Настройки пользователя: {user.name}</h2>
<p>Права доступа: {permissions.join(', ')}</p>
</div>
);
}
Ключевые моменты:
Outlet.useOutletContext упрощает передачу
данных, избавляя от необходимости прокидывать пропсы через несколько
уровней компонентов.Контекст может зависеть от состояния родительского компонента. Например:
import { useState } from 'react';
import { Outlet } from 'react-router-dom';
function Dashboard() {
const [theme, setTheme] = useState('light');
return (
<div>
<h1>Панель управления</h1>
<button onCl ick={() => setTheme(theme === 'light' ? 'dark' : 'light')}>
Сменить тему
</button>
<Outlet context={{ theme }} />
</div>
);
}
Дочерние компоненты автоматически будут получать обновлённый контекст при изменении состояния родителя:
function SettingsPanel() {
const { theme } = useOutletContext();
return <div>Текущая тема: {theme}</div>;
}
Таким образом обеспечивается реактивная передача данных через вложенные маршруты без использования глобального состояния вроде Redux.
При использовании TypeScript можно задать интерфейс для контекста, что повышает безопасность кода:
interface DashboardContext {
user: { name: string; id: number };
permissions: string[];
}
const context: DashboardContext = {
user: { name: 'Иван', id: 1 },
permissions: ['read', 'write'],
};
<Outlet context={context} />
В дочернем компоненте:
const { user, permissions } = useOutletContext<DashboardContext>();
Типизация позволяет:
import { BrowserRouter, Routes, Route } from 'react-router-dom';
function App() {
const currentUser = { name: 'Анна', id: 42 };
const userPermissions = ['read', 'write'];
return (
<BrowserRouter>
<Routes>
<Route path="/" element={<Dashboard />}>
<Route index element={<Home />} />
<Route path="settings" element={<UserSettings />} />
<Route path="profile" element={<UserProfile />} />
</Route>
</Routes>
</BrowserRouter>
);
}
function Dashboard() {
const currentUser = { name: 'Анна', id: 42 };
const userPermissions = ['read', 'write'];
return (
<div>
<h1>Панель управления</h1>
<Outlet context={{ user: currentUser, permissions: userPermissions }} />
</div>
);
}
В этом примере все дочерние маршруты (Home,
UserSettings, UserProfile) получают одинаковый
контекст, что позволяет им использовать данные пользователя и права
доступа без лишней передачи пропсов.
Контекст через Outlet — мощный инструмент для
организации структуры данных в сложных приложениях с вложенной
маршрутизацией. Он позволяет создавать чистую и поддерживаемую
архитектуру без громоздкой передачи пропсов через несколько уровней
компонентов.