Итак, у меня есть маршрут, как показано ниже, в приложении js
import React from "react";
import Login from "./pages/Login";
import { BrowserRouter, Routes, Route } from "react-router-dom";
import Dashboard from "./pages/Dashboard";
import "./App.css";
function App() {
return (
<div className = "App">
<BrowserRouter>
<Routes>
<Route exact path = "/" element = {<Dashboard />}>
<Route path = "/login" element = {<Login />} />
{/* <Route path = "*" element = {<Login />} /> */}
</Route>
</Routes>
</BrowserRouter>
</div>
);
}
export default App;
он работает, когда путь "/" показывает только страницу панели инструментов, но когда я меняю путь с помощью "/login", вместо отображения страниц входа он по-прежнему показывает страницы панели инструментов, может кто-нибудь объяснить это мне... , даже "*" вообще не работает, когда я меняю его на незарегистрированный путь, он все еще показывает страницу панели инструментов...
Вот код компонента боковой панели:
import React, { useState } from "react";
import { Fragment } from "react";
import { Route, Link } from "react-router-dom";
import {
MdOutlineSpaceDashboard,
MdOutlineStorage,
MdOutlineFactCheck,
MdOutlineCalculate,
MdStickyNote2,
MdAssignmentTurnedIn,
MdOutlineDynamicForm,
MdOutlineArrowDropDown,
} from "react-icons/md";
import { BsChevronDown, BsArrowLeftShort } from "react-icons/bs";
import Logo_Nabati from "../assets/logo-nabati.svg";
const menuItems = [
{ id: 1, label: "Dashboard", icon: MdOutlineSpaceDashboard, link: "/" },
{
id: 2,
label: "Master Data",
icon: MdOutlineStorage,
iconArrow: MdOutlineArrowDropDown,
link: "",
subMenu: true,
subMenuItems: [
{ id: 8, label: "KSBT", link: "/MasterData/list/KSBT" },
{ id: 9, label: "SQ01_RM", link: "/MasterData" },
{ id: 10, label: "SQ01_PM", link: "/MasterData" },
{ id: 11, label: "Depre", link: "/MasterData" },
{ id: 12, label: "OMC", link: "/MasterData" },
{ id: 13, label: "Premix", link: "/MasterData" },
{ id: 14, label: "Routing", link: "/MasterData" },
{ id: 15, label: "MP", link: "/MasterData" },
],
},
{ id: 3, label: "Check COGM", icon: MdOutlineFactCheck, link: "/checkcogm" },
{
id: 4,
label: "Calculation",
icon: MdOutlineCalculate,
link: "/calculation",
},
{
id: 5,
label: "Draft Calculation",
icon: MdStickyNote2,
link: "/draft",
},
{ id: 6, label: "Approved", icon: MdAssignmentTurnedIn, link: "/approval" },
{ id: 7, label: "Task Activity", icon: MdOutlineDynamicForm, link: "/task" },
];
const Sidebar = () => {
const [open, setOpen] = useState(false);
const [submenuOpen, setSubmenuOpen] = useState(false);
return (
<div className = "flex">
<div
className = {` bg-yellow-400 h-screen p-5 pt-8 ${
open
? "w-50 ease-out delay-150 peer-focus:left-0 duration-200"
: "w-20 ease-out delay-150 peer-focus:left-0 duration-200"
} duration-300 relative`}
>
<BsArrowLeftShort
className = {` bg-white text-yellow-300 text-3xl rounded-full absolute -right-3 top-9 border border-yellow-300 cursor-pointer delay-150 duration-200 ${
!open && "rotate-180"
}`}
onClick = {() => setOpen(!open)}
/>
<div className = {`inline-flex`}>
<img src = {Logo_Nabati} width = {115} height = {65} alt = "logo Nabati" />
</div>
<ul className = "pt-8">
{menuItems.map(
({ icon: Icon, iconArrow: IconArrow, ...menu }, index) => (
<Fragment key = {index}>
<Link to = {menu.link}>
<li className = "text-white text-sm text-justify flex items-center gap-x-4 cursor-pointer p-2 hover:bg-red-600 rounded-md mt-2">
<Icon className = "text-2xl text-white group-hover:text-red-600" />
<span
className = {`text-base font-mendium flex-1 duration-200 ${
!open && "hidden"
} `}
>
{menu.label}
</span>
{menu.subMenu && (
<BsChevronDown
className = {`text-base font-mendium duration-200 ${
!open && "hidden"
} ${submenuOpen && "rotate-180"}`}
onClick = {() => {
setSubmenuOpen(!submenuOpen);
}}
/>
)}
</li>{" "}
</Link>
{menu.subMenu && submenuOpen && open && (
<ul>
{menu.subMenuItems.map((subMenuItem, j) => (
<Link to = {subMenuItem.link}>
<li
key = {subMenuItem.id}
className = "text-white text-sm flex items-center gap-x-4 cursor-pointer p-0.5 px-12 hover:bg-red-500 rounded-md"
>
{subMenuItem.label}
</li>{" "}
</Link>
))}
</ul>
)}
</Fragment>
)
)}
</ul>
</div>
</div>
);
};
export default Sidebar;
и вот страница приборной панели:
import Layout from "../containers/layout";
const Dashboard = () => {
return (
<Layout>
<>Dasboard</>
</Layout>
);
};
export default Dashboard;
вот страница макета:
import { Sidebar } from "../components";
const Layout = ({ children }) => {
return (
<div className = "flex flex-row justify-start">
<Sidebar />
<div className = "bg-white flex-1 pl-4 pt-4 w-full text-red-600">
{children}
<Outlet/>
</div>
</div>
);
};
export default Layout;
вот моя страница входа:
import { FaUser, FaLock, FaUserLock } from "react-icons/fa";
import logo_nabati from "../assets/logo-nabati.svg";
import { connect } from "react-redux";
import { useState, useEffect, useRef } from "react";
import { useDispatch, useSelector } from "react-redux";
const required = (value) => {
if (!value) {
return (
<div className = "alert alert-danger" role = "alert">
This field is required!
</div>
);
}
};
const Login = (props) => {
const initState = {
newAttribs: { ...props.test },
};
const form = useRef();
const checkBtn = useRef();
const [userList, setUserList] = useState(initState);
const [username, setUsername] = useState("");
const [password, setPassword] = useState("");
const [loading, setLoading] = useState(false);
const dispatch = useDispatch();
useEffect(() => {
setUserList((userList) => ({
...userList,
newAttribs: { ...props.test },
}));
}, [props.test]);
const onChangeUsername = (e) => {
const username = e.target.value;
setUsername(username);
};
const onChangePassword = (e) => {
const password = e.target.value;
setPassword(password);
};
console.info("userList now", userList);
const loginSubmit = (e) => {
e.preventDefault();
console.info("=================================== = ");
console.info(username, password);
console.info("=================================== = ");
};
return (
<div>
{/* container */}
<div className = "bg-gradient-to-r from-yellow-400 block h-screen items-center justify-center p-4 pt-32 md:flex">
{/* login.card */}
<div className = " bg-no-repeat bg-left bg-image flex flex-col items-center max-w-screen-lg overflow-hidden rounded-lg shadow-lg text-white w-full md:flex-row">
{/* logo */}
<div className = "backdrop-blur-sm backdrop-filter flex flex-col items-center justify-center p-4 text-dark w-full md:w-1/2">
<h1 className = "font-medium text-3xl">COGM Calculation</h1>
<p className = "italic text-lg">For Manufacturing Cost Controller</p>
</div>
{/* form */}
<div className = "bg-white flex flex-col items-center p-4 space-y-8 w-full md:w-1/2">
{/* title */}
<div className = "flex flex-col items-center">
<h1 className = "font-medium text-yellow-500 text-xl">Welcome</h1>{" "}
<img
className = "m-2"
src = {logo_nabati}
width = {123}
height = {75}
alt = "logo Nabati"
/>
<p className = "text-gray-600">
<strong>Login to COGM Page</strong>
</p>
</div>
{/* input */}
<form
onSubmit = {loginSubmit}
className = "flex flex-col items-center space-y-3 pt-0"
>
<div className = "relative">
<span className = "absolute flex inset-y-0 items-center pl-4 text-gray-400">
<FaUser></FaUser>
</span>
<input
className = "border border-gray-300 outline-none text-black placeholder-gray-400 pl-9 pr-4 py-1 rounded-md transition focus:ring-2 focus:ring-yellow-300"
placeholder = "Username...."
type = "text"
onChange = {onChangeUsername}
validations = {[required]}
></input>
</div>
<div className = "relative">
<span className = "absolute flex inset-y-0 items-center pl-4 text-gray-400">
<FaLock></FaLock>
</span>
<input
className = "border border-gray-300 outline-none text-black placeholder-gray-400 pl-9 pr-4 py-1 rounded-md transition focus:ring-2 focus:ring-yellow-300"
placeholder = "Password...."
type = "password"
onChange = {onChangePassword}
validations = {[required]}
></input>
</div>
<div className = "items-left">
<button
className = "bg-yellow-500 font-medium inline-flex items-center px-3 py-1 rounded-md shadow-sm text-white hover:bg-yellow-600 pr-100"
type = "submit"
ref = {checkBtn}
>
<FaUserLock className = "mr-2"></FaUserLock>
Sign In
</button>
</div>
</form>
{/* button Link */}
<div className = "flex flex-col items-center text-gray-600">
<p className = "italic">Forget password</p>
</div>
</div>
</div>
</div>
</div>
);
};
const mapStateToProps = (state) => ({
test: state.Auth,
});
export default connect(mapStateToProps)(Login);
когда я помещаю выход на страницу макета, моя страница превращается в это:
(Я полагаю, вы используете React Router v6)
Поскольку ваш маршрут входа находится внутри панели инструментов:
<Route exact path = "/" element = {<Dashboard />}>
<Route path = "/login" element = {<Login />} />
</Route>
Просто переместите вложенный логин наружу: (в v6 нет exact
)
<Routes>
<Route path = "/" element = {<Dashboard />} />
<Route path = "login" element = {<Login />} />
</Routes>
Если вы хотите иметь несколько вложенных маршрутов на панели инструментов, например /dashboard/profile
:
<Routes>
<Route path = "/" element = {<Dashboard />}>
<Route path = "profile" element = {<Profile />} />
</Route>
<Route path = "login" element = {<Login />} />
</Routes>
[Обновление] Я думаю, что это, вероятно, то, что вы хотите:
<Routes>
<Route path = "/" element = {<Layout />}>
<Route index element = {<Dashboard />} />
</Route>
<Route path = "login" element = {<Login />} />
</Routes>
В этом случае вам не нужен {children}
в вашем макете.
Если вы не используете Layout в определениях маршрута, удалите <Outlet/>
из Layout.
Еще один вариант — определить макет в ваших маршрутах. Я добавил пример в ответ.
это работает, можете ли вы объяснить мне, почему react doom v6 немного сбивает с толку, что мы должны использовать oulet
Вот некоторые пояснения от команды react-router twitter.com/MustafaHaddara/status/1456048868752252929
теперь проблема в том, что компонент приборной панели перемещается ниже макета.