Вывод компонента при нажатии на кнопку в боковом меню в React
Я хотела сделать боковое меню, в котором при нажатии на каждую кнопку открывался бы свой компонент. Для этого взяла готовый шаблон https://www.creative-tim.com/product/light-bootstrap-dashboard-react, в отдельном проекте он работает хорошо, но при попытке добавить это в свой проект (реакт 18 версии) возникают ошибки из-за разных версий. В итоге мне удалось убрать все ошибки и осталась одна проблема с роутингом: не могу понять или найти в интернете как это сделать в новой версии реакта. На старой версии переход по компонентам осуществлялся на этой строчке: <Route path="/admin" render={(props) => <AdminLayout {...props} />} />. Но при запуске проекта на 18 версии при переходе на /admin просто белый экран. Удалось сделать чтобы /admin открывалось корректно таким образом: <Route path="/admin" element={<AdminLayout />} />, но при нажатии на кнопки в боковом меню не происходит открытие компонентов, то есть посредине просто белый экран. При этом отдельно на странице эти компоненты открываются. Вопрос в том, как переписать эту строчку, чтобы компоненты выводились на страницу.
Вот как открывается страница сейчас (красным выделено где должны выводиться компоненты, например dashboard):
А вот как должно открываться (если запускать отдельно с установленной нужной версией):
Как я думаю проблема в этой одной строке, о которой ранее шла речь. Ниже предоставляю минимальный код.
index.js:
import React from "react";
import { createRoot } from 'react-dom/client';
import App from "./App";
import Modal from "react-modal";
Modal.setAppElement("#root");
const container = document.getElementById('root');
const root = createRoot(container);
root.render(<App/>);
App.js:
import React from "react";
import { BrowserRouter as Router, Routes, Route } from "react-router-dom";
...
import AdminLayout from "layouts/Admin.js";
export default function App() {
return (
<>
<Router>
<Routes>
<Route path="/admin" element={<AdminLayout />} />
{/* Рабочий вариант на старой версии */}
{/* <Route path="/admin" render={(props) => <AdminLayout {...props} />} /> */}
</Routes>
</Router>
</>
);
}
Admin.js:
import React, { Component } from "react";
import { useLocation, Route, Routes } from "react-router-dom";
import AdminNavbar from "components/Navbars/AdminNavbar";
import Footer from "components/Footer/Footer";
import Sidebar from "components/Sidebar/Sidebar";
import FixedPlugin from "components/FixedPlugin/FixedPlugin.js";
import routes from "routes.js";
import sidebarImage from "assets/img/sidebar-3.jpg";
function Admin() {
const [image, setImage] = React.useState(sidebarImage);
const [color, setColor] = React.useState("black");
const [hasImage, setHasImage] = React.useState(true);
const location = useLocation();
const mainPanel = React.useRef(null);
const getRoutes = (routes) => {
return routes.map((prop, key) => {
if (prop.layout === "/admin") {
return (
<Route
path={prop.layout + prop.path}
render={(props) => <prop.component {...props} />}
key={key}
/>
);
} else {
return null;
}
});
};
React.useEffect(() => {
document.documentElement.scrollTop = 0;
document.scrollingElement.scrollTop = 0;
mainPanel.current.scrollTop = 0;
if (
window.innerWidth < 993 &&
document.documentElement.className.indexOf("nav-open") !== -1
) {
document.documentElement.classList.toggle("nav-open");
var element = document.getElementById("bodyClick");
element.parentNode.removeChild(element);
}
}, [location]);
return (
<>
<div className="wrapper">
<Sidebar color={color} image={hasImage ? image : ""} routes={routes} />
<div className="main-panel" ref={mainPanel}>
<AdminNavbar />
<div className="content">
<Routes>{getRoutes(routes)}</Routes>
</div>
<Footer />
</div>
</div>
<FixedPlugin
hasImage={hasImage}
setHasImage={() => setHasImage(!hasImage)}
color={color}
setColor={(color) => setColor(color)}
image={image}
setImage={(image) => setImage(image)}
/>
</>
);
}
export default Admin;
Ответы (1 шт):
Открываем первый премер роутера со стражем.
https://github.com/remix-run/react-router/blob/dev/examples/auth/src/App.tsx
<Routes>
<Route element={<Layout />}>
<Route path="/" element={<PublicPage />} />
<Route path="/login" element={<LoginPage />} />
<Route path="/protected" element={
<RequireAuth>
<ProtectedPage />
</RequireAuth> } />
</Route>
</Routes>
И вам, и программисту после вас сразу понятно, что что-бы попасть в /protected нужно иметь доступы. Все роутеры в одном месте и никакой кашицы. Вообще хорошая реализация Guard есть у меня на codepen.
https://codepen.io/latdev/pen/qBJGmwr
Если чутка доработать напильником, то можно любые Permissions реализовать такие как
<Guard require="one" anyOf={[]} requireAll={[]} />
И использовать его не только в роутинге.
А еще расскажу по секрету, что в Guard можно запихнуть не только <ProtectedPage/> но и <Route/> целиком и даже массив из <Route/>
<Routes>
<Route />
<Route />
<Guard require="admin" />
<Route />
<Route />
</Guard>
</Routes>
Что мы получаем на выходе? Просто шикарный и читаемый код, с которым приятно работать без костылей с массивом.
Расскажу еще одну интересную фишку, что новый react-router-dom а именно 6.11 собирает роутер через массив и createBrowserRouter
https://reactrouter.com/en/main/start/tutorial
Ps: Хотя лично меня вот конкретно так бесит в React что - они от версии к версии переделывают прям все целиком. И портировать код без боли и слез прям никак не получается особенно на крупных проектах.
Pss: react-modal кстати лучше сразу выкинуть в печь, и заменить его на HTML тэг Dialog - https://developer.mozilla.org/en-US/docs/Web/HTML/Element/dialog
Добавлено 30.05
Я так полагаю что с 6.х роутером вы столкнулись недавно, все эти вопросы автоматом отваливаются когда понимаешь что такое Outlet и вложенность Route. На ваше счастье на YT уже ответили на многие ваши вопросы.
Первая ссылка это пояснение Routes, Route, NavLink, Link
Вторая ссылка это рассказ о вложенности, layout и outlet
Вообще крайне рекомендую автора видео к просмотру! Он рассказывает умные и полезные вещи, причем не на уровне накрутить просмотры и поскорее отснять следующее говно, а именно выбирая темы по наростанию, и рассказывая разные нюансы. При этом он это делает по документации, и не несет чушь.

