我有一个虚拟的工作板 Web 应用程序,它使用 React 和 Joy UI 作为前端和 UI。我使用 Joy UI 的 Snackbar 组件在用户执行某些操作(注册、登录等)后临时弹出一条消息。在 Snackbar 上,我将
autoHideDuration
属性设置为 {3000}
,这样它就会在 3 秒后消失。如果用户单击关闭图标或 Snackbar 之外的某个位置,Snackbar 也会消失。
但是,如果用户在 Snackbar 出现后快速导航到其他页面,然后按浏览器中的“后退”按钮,则 Snackbar 会重新出现,并且仅在初始计时器到期后消失。而且,计时器似乎不包括用户在其他页面上花费的时间,因此即使用户在其他页面停留超过 3 秒,Snackbar 也可以在导航回原始页面后重新出现。
这是一种不受欢迎的行为,如果用户导航离开最初呈现 Snackbar 的页面,我希望 Snackbar 永远消失。
我的自定义 SnackBarAlert 组件如下:
import { useState, useEffect, useContext } from "react";
import { AuthContext } from "../store/AuthContext";
import { ProfileContext } from "../store/ProfileContext";
import { FeedbackContext } from "../store/FeedbackContext";
import { SnackBarAlert } from "./SnackBarAlert";
import { Container } from "@mui/joy";
export const SnackBarContainer = () => {
const { authStatus, changeAuthStatus } = useContext(AuthContext);
const { profile, changeProfile } = useContext(ProfileContext);
const { feedback, changeFeedback } = useContext(FeedbackContext);
const [loggedInAlert, setLoggedInAlert] = useState(false);
const [loggedOutAlert, setLoggedOutAlert] = useState(false);
const [registeredAlert, setRegisteredAlert] = useState(false);
const [editedProfileAlert, setEditedProfileAlert] = useState(false);
const [appliedAlert, setAppliedAlert] = useState(false);
const [postedVacancyAlert, setPosterVacancyAlert] = useState(false);
const [editedVacancyAlert, setEditedVacancyAlert] = useState(false);
const [deletedVacancyAlert, setDeletedVacancyAlert] = useState(false);
const [postedFeedbackAlert, setPostedFeedbackAlert] = useState(false);
useEffect(() => {
authStatus.justLoggedOut && setLoggedOutAlert(true);
authStatus.justLoggedIn && setLoggedInAlert(true);
profile.justRegistered && setRegisteredAlert(true);
profile.justEditedProfile && setEditedProfileAlert(true);
profile.justApplied && setAppliedAlert(true);
profile.justPostedVacancy && setPosterVacancyAlert(true);
profile.justEditedVacancy && setEditedVacancyAlert(true);
profile.justDeletedVacancy && setDeletedVacancyAlert(true);
feedback && setPostedFeedbackAlert(true);
}, []);
return (
<Container>
<SnackBarAlert
open={loggedInAlert}
text="You successfully logged in!"
onClose={() => {
setLoggedInAlert(false);
changeAuthStatus({
...authStatus,
justLoggedIn: null
});
}}
/>
<SnackBarAlert
open={loggedOutAlert}
text="You logged out!"
onClose={() => {
setLoggedOutAlert(false);
changeAuthStatus({
...authStatus,
justLoggedOut: null
});
}}
/>
<SnackBarAlert
open={registeredAlert}
text="You succesfully registered! Now, please log in to your account."
onClose={() => {
setRegisteredAlert(false);
changeProfile({
...profile,
justRegistered: null
});
}}
/>
<SnackBarAlert
open={editedProfileAlert}
text="You successfully edited your profile!"
onClose={() => {
setEditedProfileAlert(false);
changeProfile({
...profile,
justEditedProfile: null
});
}}
/>
<SnackBarAlert
open={appliedAlert}
text="You succesfully applied for a vacancy"
onClose={() => {
setAppliedAlert(false);
changeProfile({
...profile,
justApplied: null
});
}}
/>
<SnackBarAlert
open={postedVacancyAlert}
text="You successfully posted a vacancy!"
onClose={() => {
setPosterVacancyAlert(false);
changeProfile({
...profile,
justPostedVacancy: null
});
}}
/>
<SnackBarAlert
open={editedVacancyAlert}
text="You successfully edited a vacancy!"
onClose={() => {
setEditedVacancyAlert(false);
changeProfile({
...profile,
justEditedVacancy: null
});
}}
/>
<SnackBarAlert
open={deletedVacancyAlert}
text="You deleted a vacancy!"
onClose={() => {
setDeletedVacancyAlert(false);
changeProfile({
...profile,
justDeletedVacancy: null
});
}}
/>
<SnackBarAlert
open={postedFeedbackAlert}
text="You successfully sent a message!"
onClose={() => {
setPostedFeedbackAlert(false);
changeFeedback(null);
}}
/>
</Container>
);
};
我的 SnackBarContainer 组合了不同的警报如下:
import { useState, useEffect, useContext } from "react";
import { AuthContext } from "../store/AuthContext";
import { ProfileContext } from "../store/ProfileContext";
import { FeedbackContext } from "../store/FeedbackContext";
import { SnackBarAlert } from "./SnackBarAlert";
import { Container } from "@mui/joy";
export const SnackBarContainer = () => {
const { authStatus, changeAuthStatus } = useContext(AuthContext);
const { profile, changeProfile } = useContext(ProfileContext);
const { feedback, changeFeedback } = useContext(FeedbackContext);
const [loggedInAlert, setLoggedInAlert] = useState(false);
const [loggedOutAlert, setLoggedOutAlert] = useState(false);
const [registeredAlert, setRegisteredAlert] = useState(false);
const [editedProfileAlert, setEditedProfileAlert] = useState(false);
const [appliedAlert, setAppliedAlert] = useState(false);
const [postedVacancyAlert, setPosterVacancyAlert] = useState(false);
const [editedVacancyAlert, setEditedVacancyAlert] = useState(false);
const [deletedVacancyAlert, setDeletedVacancyAlert] = useState(false);
const [postedFeedbackAlert, setPostedFeedbackAlert] = useState(false);
useEffect(() => {
authStatus.justLoggedOut && setLoggedOutAlert(true);
authStatus.justLoggedIn && setLoggedInAlert(true);
profile.justRegistered && setRegisteredAlert(true);
profile.justEditedProfile && setEditedProfileAlert(true);
profile.justApplied && setAppliedAlert(true);
profile.justPostedVacancy && setPosterVacancyAlert(true);
profile.justEditedVacancy && setEditedVacancyAlert(true);
profile.justDeletedVacancy && setDeletedVacancyAlert(true);
feedback && setPostedFeedbackAlert(true);
}, []);
return (
<Container>
<SnackBarAlert
open={loggedInAlert}
text="You successfully logged in!"
onClose={() => {
setLoggedInAlert(false);
changeAuthStatus({
...authStatus,
justLoggedIn: null
});
}}
/>
<SnackBarAlert
open={loggedOutAlert}
text="You logged out!"
onClose={() => {
setLoggedOutAlert(false);
changeAuthStatus({
...authStatus,
justLoggedOut: null
});
}}
/>
<SnackBarAlert
open={registeredAlert}
text="You succesfully registered! Now, please log in to your account."
onClose={() => {
setRegisteredAlert(false);
changeProfile({
...profile,
justRegistered: null
});
}}
/>
<SnackBarAlert
open={editedProfileAlert}
text="You successfully edited your profile!"
onClose={() => {
setEditedProfileAlert(false);
changeProfile({
...profile,
justEditedProfile: null
});
}}
/>
<SnackBarAlert
open={appliedAlert}
text="You succesfully applied for a vacancy"
onClose={() => {
setAppliedAlert(false);
changeProfile({
...profile,
justApplied: null
});
}}
/>
<SnackBarAlert
open={postedVacancyAlert}
text="You successfully posted a vacancy!"
onClose={() => {
setPosterVacancyAlert(false);
changeProfile({
...profile,
justPostedVacancy: null
});
}}
/>
<SnackBarAlert
open={editedVacancyAlert}
text="You successfully edited a vacancy!"
onClose={() => {
setEditedVacancyAlert(false);
changeProfile({
...profile,
justEditedVacancy: null
});
}}
/>
<SnackBarAlert
open={deletedVacancyAlert}
text="You deleted a vacancy!"
onClose={() => {
setDeletedVacancyAlert(false);
changeProfile({
...profile,
justDeletedVacancy: null
});
}}
/>
<SnackBarAlert
open={postedFeedbackAlert}
text="You successfully sent a message!"
onClose={() => {
setPostedFeedbackAlert(false);
changeFeedback(null);
}}
/>
</Container>
);
};
并且,这是我的登录页面组件的示例,它使用 Snackbars 之一:
import { useContext, useEffect } from "react";
import { Link as RouterLink, useNavigate } from "react-router-dom";
import { Container, Typography, Card, CardContent, CardActions, Stack, Link } from "@mui/joy";
import { AuthContext } from "../store/AuthContext";
import { LoginForm } from "../components/LoginForm";
import { SnackBarContainer } from "../components/SnackBarContainer";
export const Login = () => {
const navigate = useNavigate();
const { authStatus } = useContext(AuthContext);
useEffect(() => {
authStatus.isLoggedIn && navigate("/");
}, []);
return (
<Container>
<Stack
justifyContent="center"
alignItems="center"
spacing={5}
sx={{ paddingY: { xs: 5, xl: 16 } }}
>
<Card variant="outlined" sx={{
width: { xs: "80%", sm: "60%", md: "40%" }
}}>
<CardContent sx={{ alignItems: "center", textAlign: "center" }}>
<LoginForm />
</CardContent>
<CardActions>
</CardActions>
</Card>
<Typography>
<Link component={RouterLink} to="/candidate-register">
Register as a candidate here
</Link>
</Typography>
<Typography>
<Link component={RouterLink} to="/recruiter-register">
Register as a recruiter here
</Link>
</Typography>
</Stack>
<SnackBarContainer />
</Container >
);
};
我的想法是,这个问题与我用于路由的React Router如何处理React应用程序中的状态有关,但我找不到解决方法。
任何帮助将不胜感激。
我认为你可以通过几种方式帮助解决这个问题。
看起来您正在渲染消息的各个
SnackBarContainer
组件。如果/当 useEffect
卸载时,使用 SnackBarContainer
清理功能设置小吃栏显示状态。
export const SnackBarContainer = () => {
const { authStatus, changeAuthStatus } = useContext(AuthContext);
const { profile, changeProfile } = useContext(ProfileContext);
const { feedback, changeFeedback } = useContext(FeedbackContext);
const [loggedInAlert, setLoggedInAlert] = useState(false);
const [loggedOutAlert, setLoggedOutAlert] = useState(false);
const [registeredAlert, setRegisteredAlert] = useState(false);
const [editedProfileAlert, setEditedProfileAlert] = useState(false);
const [appliedAlert, setAppliedAlert] = useState(false);
const [postedVacancyAlert, setPosterVacancyAlert] = useState(false);
const [editedVacancyAlert, setEditedVacancyAlert] = useState(false);
const [deletedVacancyAlert, setDeletedVacancyAlert] = useState(false);
const [postedFeedbackAlert, setPostedFeedbackAlert] = useState(false);
useEffect(() => {
authStatus.justLoggedOut && setLoggedOutAlert(true);
authStatus.justLoggedIn && setLoggedInAlert(true);
profile.justRegistered && setRegisteredAlert(true);
profile.justEditedProfile && setEditedProfileAlert(true);
profile.justApplied && setAppliedAlert(true);
profile.justPostedVacancy && setPosterVacancyAlert(true);
profile.justEditedVacancy && setEditedVacancyAlert(true);
profile.justDeletedVacancy && setDeletedVacancyAlert(true);
feedback && setPostedFeedbackAlert(true);
return () => {
setLoggedOutAlert(false);
setLoggedInAlert(false);
setRegisteredAlert(false);
setEditedProfileAlert(false);
setAppliedAlert(false);
setPosterVacancyAlert(false);
setEditedVacancyAlert(false);
setDeletedVacancyAlert(false);
setPostedFeedbackAlert(false);
};
}, []);
return (
...
);
};
使用导航操作可以更好地维护历史堆栈。例如,假设
Login
组件在 "/login"
上呈现并成功进行身份验证,则当前代码将推送到 "/"
。如果他们返回,他们会再次降落在 "/login"
上。使用 REPLACE 操作有助于防止不良的后退导航操作,以便用户无法导航回现在无效的页面。这个想法是为了防止用户导航回最初启动 toast 的页面。
示例:
export const Login = () => {
const navigate = useNavigate();
const { authStatus } = useContext(AuthContext);
useEffect(() => {
// Redirect to "/" instead of pushing another history entry
authStatus.isLoggedIn && navigate("/", { replace: true });
}, []);
...
};