我在网站上实现用户登录功能时遇到了 React 上下文问题。用户可以作为虚拟用户登录,我已经使用 React 上下文实现了这一点。但是,在用户登录并离开页面后,上下文不会持续存在,使我相信该组件正在重新渲染。
GitHub:GitHub 存储库
此外,您可以在直播网站上体验该问题:直播网站
如果您能帮助我理解为什么在离开页面后上下文没有持续存在,我将不胜感激。谢谢您的帮助。
import { createContext, useState } from "react";
export const UserContext = createContext();
export const UserProvider = (props) => {
const [user, setUser] = useState("grumpy19");
return (
<UserContext.Provider value={{ user, setUser }}>
{props.children}
</UserContext.Provider>
);
};
import { useEffect, useState } from "react";
import { getUsers } from "../../utils/utils";
import { UserContext } from "../../contexts/UserContent";
import { useContext } from "react";
import "./Users.css";
import Spinner from "react-bootstrap/Spinner";
import { Card, CardGroup } from "react-bootstrap";
import { Badge } from "react-bootstrap";
import Stack from "react-bootstrap/Stack";
export default function Users() {
const [users, setUsers] = useState([]);
const [isLoading, setIsLoading] = useState(false);
const [err, setErr] = useState(null);
const { setUser, user } = useContext(UserContext);
function handleAvatarClick(username) {
setUser(username);
}
useEffect(() => {
setIsLoading(true);
setErr(false);
getUsers()
.then(({ users }) => {
setUsers(users);
setIsLoading(false);
})
.catch((err) => {
setIsLoading(false);
setErr(err);
});
}, []);
if (err)
return (
<div>
<h1>Whoops</h1>
<h2>Status: {err.status}</h2>
<h2>{err.msg}</h2>
</div>
);
return (
<div className="user-container">
<h2 id="user-heading">Users</h2>
<p id="user-desc">Click on a users image to log in</p>
<p id="current-user">
Hello <Badge bg="dark">{user}</Badge> !
</p>
{isLoading ? (
<Spinner animation="border" variant="primary" className="spinner" />
) : null}
<CardGroup id="users-list">
<ul>
{users.map((person, index) => {
return (
<Card
key={index}
className="user-card"
onClick={() => {
handleAvatarClick(person.username);
}}
>
<Stack className="user-info" direction="horizontal" gap={3}>
<div className="p-2">{person.name}</div>
<div className="p-2 ms-auto">
{" "}
<Badge>{person.username}</Badge>
</div>
</Stack>
<Card.Img src={person.avatar_url} />
</Card>
);
})}
</ul>
</CardGroup>
</div>
);
}
我在之前的项目中实现了类似的代码,并且运行没有任何问题。
import { createContext, useState } from "react";
export const UserContext = createContext();
export const UserProvider = (props) => {
const [user, setUser] = useState("Paul-R");
return (
<UserContext.Provider value={{ user, setUser }}>
{props.children}
</UserContext.Provider>
);
};
import { useEffect, useState } from "react";
import "./Users.css";
import { getUsers } from "../../utils.js/api";
import { UserContext } from "../../contexts/UserContent";
import { useContext } from "react";
export default function Users() {
const [users, setUsers] = useState([]);
const [isLoading, setIsLoading] = useState(false);
const [err, setErr] = useState(null);
const { setUser } = useContext(UserContext);
function handleAvatarClick(username) {
setUser(username);
}
useEffect(() => {
setIsLoading(true);
setErr(false);
getUsers()
.then(({ users }) => {
setUsers(users);
setIsLoading(false);
})
.catch((err) => {
setIsLoading(false);
setErr(err);
});
}, []);
if (isLoading) return <p>Loading...</p>;
if (err)
return (
<div>
<h1>Whoops</h1>
<h2>Status: {err.status}</h2>
<h2>{err.msg}</h2>
</div>
);
return (
<div>
<h1>Users</h1>
<p>Click on a users image to log in</p>
<ul>
{users.map((user) => {
return (
<li key={user.username}>
<p>username: {user.username}</p>
<p>kudos: {user.kudos}</p>
<img
src={user.avatar_url}
alt=""
width="100"
onClick={() => {
handleAvatarClick(user.username);
}}
/>
</li>
);
})}
</ul>
</div>
);
}
问题是react-bootstrap的
<Nav.Link>
组件不知道你正在使用react-router,因此不与它集成。当您单击链接时,它会进行页面刷新,这会重置应用程序中的所有状态。
您可以独立使用react-router的Link组件,如下所示:
import { Link } from 'react-router';
// ...
<Link to="/">Home</Link>
或者如果你想继续使用react-bootstrap的Nav.Link,可以使用
as
属性来告诉它使用不同的组件进行渲染:
<Nav.Link as={Link} to="/">Home</Nav.Link>
或者,还有一种选择,您可以编写一个 onClick 处理程序并让它从
useNavigate
: 调用该函数
export default function Navigation() {
const navigate = useNavigate)9;
// ...
<Nav.Link onClick={() => navigate("/")}>Home</Nav.Link>
}