React、React Router、Joy UI:如何禁用导航离开和返回后重新出现的小吃栏?

问题描述 投票:0回答:1

我有一个虚拟的工作板 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应用程序中的状态有关,但我找不到解决方法。

任何帮助将不胜感激。

该应用程序已上线,可以在此处访问。完整代码可在 GitHub here 上获取。

reactjs material-ui react-router
1个回答
0
投票

我认为你可以通过几种方式帮助解决这个问题。

  1. 看起来您正在渲染消息的各个

    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 (
        ...
      );
    };
    
  2. 使用导航操作可以更好地维护历史堆栈。例如,假设

    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 });
      }, []);
    
      ...
    };
    
© www.soinside.com 2019 - 2024. All rights reserved.