React Router предоставляет гибкую систему маршрутизации, позволяющую создавать сложные интерфейсы с вложенными маршрутами и управлять состоянием контекста на разных уровнях приложения. Понимание того, как наследуется контекст в маршрутах, критично для построения масштабируемой архитектуры.
В React контекст используется для передачи данных через дерево
компонентов без необходимости пробрасывать пропсы на каждом уровне.
React Router интегрируется с контекстом, создавая собственный контекст
маршрутизации, который содержит информацию о текущем пути, параметрах
маршрута и истории навигации. Этот контекст доступен компонентам,
расположенным внутри <Routes> и
<Route>.
import { BrowserRouter, Routes, Route, useParams } from 'react-router-dom';
function UserProfile() {
const { userId } = useParams();
return <div>Профиль пользователя {userId}</div>;
}
function App() {
return (
<BrowserRouter>
<Routes>
<Route path="/user/:userId" element={<UserProfile />} />
</Routes>
</BrowserRouter>
);
}
В примере выше useParams получает доступ к контексту
маршрута, автоматически наследуя параметры текущего URL.
Вложенные маршруты создают иерархию компонентов, где дочерние маршруты автоматически наследуют контекст родителя. Это особенно полезно при построении интерфейсов с несколькими уровнями навигации, например, панелью администратора с разделами и подразделами.
function Dashboard() {
return (
<div>
<h1>Панель администратора</h1>
<Routes>
<Route path="users" element={<UserList />} />
<Route path="settings" element={<Settings />} />
</Routes>
</div>
);
}
Дочерние маршруты users и settings
автоматически получают контекст родительского маршрута, включая историю
и состояние навигации. Это позволяет использовать хуки вроде
useNavigate и useLocation на любом уровне
вложенности.
Контекст маршрута включает параметры URL. При вложенных маршрутах
параметры родителя могут быть доступны дочерним компонентам. Например,
если маршрут родителя содержит параметр :projectId, все
вложенные маршруты могут его использовать:
function Project() {
const { projectId } = useParams();
return (
<div>
<h2>Проект {projectId}</h2>
<Routes>
<Route path="tasks" element={<Tasks />} />
</Routes>
</div>
);
}
function Tasks() {
const { projectId } = useParams();
return <div>Задачи проекта {projectId}</div>;
}
Здесь компонент Tasks наследует параметр
projectId из контекста маршрута родителя
Project.
<Outlet> используется для рендеринга вложенных
маршрутов. Он также обеспечивает передачу контекста родителя всем
вложенным маршрутам:
function Layout() {
return (
<div>
<Header />
<Outlet />
<Footer />
</div>
);
}
function App() {
return (
<BrowserRouter>
<Routes>
<Route path="/" element={<Layout />}>
<Route path="home" element={<Home />} />
<Route path="about" element={<About />} />
</Route>
</Routes>
</BrowserRouter>
);
}
Все компоненты внутри <Outlet> получают доступ к
контексту маршрута, определенному на уровне Layout.
React Router позволяет создавать пользовательский контекст поверх маршрутов. Например, состояние авторизации можно хранить в контексте на уровне корневого маршрута, и оно будет доступно всем вложенным маршрутам:
const AuthContext = React.createContext();
function AuthProvider({ children }) {
const [user, setUser] = React.useState(null);
return (
<AuthContext.Provider value={{ user, setUser }}>
{children}
</AuthContext.Provider>
);
}
function App() {
return (
<BrowserRouter>
<AuthProvider>
<Routes>
<Route path="/dashboard/*" element={<Dashboard />} />
</Routes>
</AuthProvider>
</BrowserRouter>
);
}
В этом случае все компоненты внутри <Dashboard> и
его дочерних маршрутов могут использовать
useContext(AuthContext) без дополнительного проброса
пропсов.
<Provider> внутри нужного компонента.useParams необходимо убедиться, что
путь маршрута действительно содержит соответствующий параметр, иначе
возвращается undefined.<Outlet> для построения макетов
страниц с повторяющимися компонентами, сохраняя контекст навигации и
параметры URL.Наследование контекста в маршрутах позволяет строить архитектуру, где данные и состояние маршрутизации доступны на любом уровне вложенности без избыточного проброса пропсов, что делает приложения более масштабируемыми и поддерживаемыми.