我在導航欄中對幾個按鈕使用選擇性渲染。首先,我檢查accessToken是否在localStorage中找到,然后只呈現這些按鈕,但當我登錄并將用戶導航到新頁面時,導航欄不會更新以顯示這些按鈕。
import React,{forwardRef, useEffect, useState} from "react";
import { logoutUser } from "@/features/userSlice";
import { NavLink, useNavigate } from "react-router-dom";
import { LogOut, Settings, User, Users, Plus } from "lucide-react";
import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar";
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuSeparator,
DropdownMenuTrigger,
} from "@/components/ui/dropdown-menu";
//********************************* getting token from localStorage********************
const token = localStorage.getItem("token");
************************************************************************************
const AvatarDropdown = () => {
return (
<>
<DropdownMenu modal={true} onOpenChang={() => setIsOpen(!isOpen)}>
<DropdownMenuTrigger className="outline-none">
<Avatar>
<AvatarImage src="https://github.com/shadcn.png" />
<AvatarFallback>CN</AvatarFallback>
</Avatar>
</DropdownMenuTrigger>
<DropdownMenuContent align="end" className="text-center">
<DropdownMenuItem
onClick={() => handleLogout()}
className="px-5 py-1 "
>
<LogOut className="mr-3" />
Logout
</DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenu>
</>
);
};
const Header = forwardRef((props, ref) => {
const navigate = useNavigate();
******************tried this re-rendering method*** doesn't work******
const [re, setRe] = useState(true);
const user = useSelector(getUserInfo);
useEffect(()=>{
setRe(!re)
},[user.accessToken])
***********************************************************************
return (
<main
className="w-full bg-orange-400 h-fit md:px-[100px] px-[40px] py-2 flex items-center justify-between box-border fixed top-0 z-10"
ref={ref}
>
<div className=" md:flex hidden w-[70%] items-center gap-5">
<div className="w-full flex flex-1 items-center justify-end gap-5">
{!token && (
<NavLink
className={({ isActive }) =>
`p-2 font-semibold rounded-md bg-teal-400
text-white hover:bg-teal-500 active:bg-teal-700
${isActive ? "border-[2px]" : ""}`
}
to="/register-login"
>
Register / Login
</NavLink>
)}
<NavLink
className={({ isActive }) =>
`p-2 font-semibold rounded-md bg-indigo-400
text-white hover:bg-indigo-500 active:bg-indigo-700
${isActive ? "border-[2px]" : ""}`
}
to="/"
>
All Memories
</NavLink>
{token && (
<NavLink
className={({ isActive }) =>
`border p-2 font-semibold rounded-md text-black
hover:bg-orange-500 active:bg-orange-700
${isActive ? "border-[2px]" : ""}`
}
to="/my-memories"
>
My Memories
</NavLink>
)}
</div>
<div>{token && <AvatarDropdown />}</div>
</div>
<div className="md:hidden flex flex-row-reverse items-center space-x-5">
{token && (
<div className="ml-3">
<AvatarDropdown />
</div>
)}
<DropdownMenu modal={true} onOpenChang={() => setIsOpen(!isOpen)}>
<DropdownMenuTrigger className="outline-none">
<i className="fa-solid fa-bars text-2xl p-2 text-black"></i>
</DropdownMenuTrigger>
<DropdownMenuContent align="end" className="text-center">
<DropdownMenuItem
onClick={() => navigate("/register-login")}
className="px-5 py-1 "
disabled={token}
>
<Plus className="mr-3" />
Register or Login
</DropdownMenuItem>
<DropdownMenuSeparator />
<DropdownMenuItem
onClick={() => navigate("/")}
className="px-5 py-1 "
>
<Users className="mr-3" />
All Memories
</DropdownMenuItem>
<DropdownMenuSeparator />
<DropdownMenuItem
onClick={() => navigate("/my-memories")}
className="px-5 py-1"
disabled={!token}
>
<User className="mr-3" />
My Memories
</DropdownMenuItem>
<DropdownMenuSeparator />
</DropdownMenuContent>
</DropdownMenu>
</div>
</main>
);
});
export default Header;
我登錄的表單組件,如果登錄成功,則將用戶導航到新頁面。
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
import { registerUser, loginUser } from "@/features/userSlice";
import { useToasts } from "@/utils/useToastHook";
import { unwrapResult } from "@reduxjs/toolkit";
import { useNavigate } from "react-router-dom";
import { useDispatch } from "react-redux";
import { Footer } from "../exporter";
import { useState } from "react";
const RegisterAndLoginForm = ({
name,
loginForm,
setLoginForm,
}) => {
const navigate = useNavigate();
const dispatch = useDispatch();
const showToast = useToasts();
const handleLoginInput = (e) => {
setLoginForm({ ...loginForm, [e.target.name]: e.target.value });
};
****************************** Handling login and then navigating to new page**********************
const handleSubmit = async(e) => {
e.preventDefault();
try {
const actionResult = await dispatch(loginUser(loginForm)).unwrap();
const result = unwrapResult(actionResult);
showToast("bg-green-700", "Success", "Login successfully.");
localStorage.setItem("token", actionResult.data.accessToken)
navigate("/my-memories");
} catch (error) {
showToast("bg-red-700", "Error", error.errorMessage);
}
};
****************************************************************************************************
return (
<main className="bg-transparent_bg w-full flex flex-col items-center box-border rounded-md">
<form
className="w-full text-center space-y-3 p-2 box-border"
onSubmit={handleSubmit}
>
<h3 className="font-extrabold text-foreground text-xl bg-slate-500 py-2 rounded-md tracking-widest">
{name}
</h3>
<label className="form__label" htmlFor="username">Username: </label>
<input
id="username"
className="input"
type="text"
placeholder="username"
name="username"
value={loginForm.username}
onChange={handleLoginInput}
required
pattern="^[^\d]*$"
title="name can not contains numbers"
/>
<label className="form__label" htmlFor="password">Password: </label>
<input
id="password"
className="input"
type="password"
placeholder="password"
name="password"
value={loginForm.password}
onChange={handleLoginInput}
required
/>
<div className="flex justify-center gap-5 py-1 box-border">
<button
type="submit"
className="bg-blue-400 w-24 px-3 py-2 rounded-md hover:bg-blue-500 active:bg-blue-600 text-white tracking-widest"
>
{name}
</button>
</div>
</form>
</main>
);
};
const LoginAndRegister = () => {
const [loginForm, setLoginForm] = useState({username: "", password: ""});
return (
<>
<div className="w-[80%] grid m-auto grid-cols-12 gap-1">
<div className="md:col-span-6 col-span-12 md:text-center md:m-0 m-auto">
<Tabs defaultValue="register" className="md:w-auto p-1">
<TabsList className="w-full">
<TabsTrigger value="register" className="w-[50%]">
Register
</TabsTrigger>
<TabsTrigger value="login" className="w-[50%]">
Login
</TabsTrigger>
</TabsList>
<TabsContent value="register" className="border rounded-md">
<RegisterAndLoginForm
name={"Register"}
/>
</TabsContent>
<TabsContent value="login" className="border rounded-md">
<RegisterAndLoginForm
name={"Login"}
loginForm={loginForm}
setLoginForm={setLoginForm}
/>
</TabsContent>
</Tabs>
</div>
<div className=" max-h-[680px] md:col-span-6 overflow-hidden rounded-lg relative md:block hidden">
<img src="login-hero.jpg" alt="login-hero" className="object-cover rounded-lg" />
</div>
</div>
<Footer />
</>
);
};
export default LoginAndRegister;
我使用的是react-router-dom v6,布局組件如下所示:
const Layout = () => {
const [headerHeight, setHeaderHeight] = useState(0);
const headerRef = useRef(null);
useEffect(() => {
if (headerRef) {
const height = headerRef.current.offsetHeight;
if (height) {
setHeaderHeight(height);
}
}
}, [headerRef.current]);
return (
<>
<Header ref={headerRef} />
<Suspense fallback={<div>Loading...</div>}>
<div className="max-w-[1484px] flex flex-col items-center m-auto">
<MemoriesHeader />
<Outlet context={[headerHeight]} />
</div>
</Suspense>
</>
);
};
export default Layout;
我嘗試了re-rendering使用狀態的頭組件,并根據條件將其設置為false和true,但這也不起作用。
你不需要把它用起來嗎?
something like