React 中的会话超时与模态
Session timeout in React with modal
我使用 react-idle-timer
创建了一个会话超时,它在第一次时运行良好,但是当我在模态警告中单击“继续会话”时,它不会将超时重置为原始设置(本例中为 30 秒)。单击继续会话后,它会每 5 秒打开一次警告模式。
SessionTimeout.js
import React, { useState, useRef } from "react";
import IdleTimer from "react-idle-timer";
import { useDispatch } from "react-redux";
import { bindActionCreators } from "redux";
import { actionCreators } from '../state/index';
import { useHistory } from "react-router-dom";
import { useSelector } from "react-redux";
import SessionTimeoutDialog from './SessionTimeoutDialog';
let countdownInterval;
let timeout = 1000 * 30 * 1;
const SessionTimeout = () => {
const idleTimer = useRef(null);
const history = useHistory();
const login = useSelector((state) => state.login); // this is just to see if a user is logged
const dispatch = useDispatch();
const { logout } = bindActionCreators(actionCreators, dispatch); // this is to logout
const [timeoutModalOpen, setTimeoutModalOpen] = useState(false);
const [timeoutCountdown, setTimeoutCountdown] = useState(0);
const onActive = () => {
// timer reset automatically.
if (!timeoutModalOpen) {
clearSessionInterval();
clearSessionTimeout();
}
};
const onIdle = () => {
const delay = 1000 * 5;
if(login.logged && !timeoutModalOpen) {
timeout = setTimeout(() => {
let countDown = 60;
setTimeoutModalOpen(true);
setTimeoutCountdown(countDown);
countdownInterval = setInterval(() => {
if (countDown > 0) {
setTimeoutCountdown(--countDown);
} else {
handleLogout();
}
}, 1000);
}, delay);
}
};
const clearSessionTimeout = () => {
clearTimeout(timeout);
};
const clearSessionInterval = () => {
clearInterval(countdownInterval);
};
const handleLogout = () => {
setTimeoutModalOpen(false);
clearSessionInterval();
clearSessionTimeout();
logout();
history.push("/login");
};
const handleContinue = () => {
setTimeoutModalOpen(false);
clearSessionInterval();
clearSessionTimeout();
};
return (
<>
<IdleTimer
ref={idleTimer}
onActive={onActive}
onIdle={onIdle}
debounce={250}
timeout={timeout}
/>
<SessionTimeoutDialog
countdown={timeoutCountdown}
onContinue={handleContinue}
onLogout={handleLogout}
open={timeoutModalOpen}
/>
</>
);
};
export default SessionTimeout;
这是我的模态(对话框)。 SessionTimeoutDialog.jsx
import React from "react";
import * as PropTypes from "prop-types";
import {
Dialog,
DialogTitle,
DialogContent,
DialogActions,
Button,
Typography,
makeStyles,
Slide
} from "@material-ui/core";
import clsx from "clsx";
import red from "@material-ui/core/colors/red";
const useStyles = makeStyles(() => ({
dialog: {
borderRadius: 0
},
button: {
borderRadius: 0,
textTransform: "none",
padding: 5
},
logout: {
color: "#fff",
backgroundColor: red[500],
"&:hover": {
backgroundColor: red[700]
}
},
countdown: {
color: red[700]
}
}));
const Transition = React.forwardRef(function Transition(props,ref) {
return <Slide direction="up" ref={ref} {...props} />;
});
export default function SessionTimeoutDialog({
open,
countdown,
onLogout,
onContinue
}) {
const classes = useStyles();
return (
<Dialog
open={open}
aria-labelledby="session-timeout-dialog"
aria-describedby="session-timeout-dialog"
classes={{ paper: classes.dialog }}
TransitionComponent={Transition}
>
<DialogTitle id="session-timeout-dialog-title">
Session Timeout
</DialogTitle>
<DialogContent>
<Typography variant="body2">
The current session is about to expire in{" "}
<span className={classes.countdown}>{countdown}</span> seconds.
</Typography>
<Typography variant="body2">{`Would you like to continue the session?`}</Typography>
</DialogContent>
<DialogActions>
<Button
onClick={onLogout}
variant="contained"
className={clsx(classes.logout, classes.button)}
>
Logout
</Button>
<Button
onClick={onContinue}
color="primary"
variant="contained"
className={classes.button}
>
Continue Session
</Button>
</DialogActions>
</Dialog>
);
}
SessionTimeoutDialog.propTypes = {
/**
* indicator whether the dialog is open/close
*/
open: PropTypes.bool.isRequired,
/**
* the countdown timer.
*/
countdown: PropTypes.number.isRequired,
/**
* callback function to handle closing action
*/
onLogout: PropTypes.func.isRequired,
/**
* callback function to handle confirm action.
*/
onContinue: PropTypes.func.isRequired
};
这是一个沙箱示例:https://codesandbox.io/s/festive-dust-dzt1t
单击“继续会话”后如何将超时设置回默认的 30 秒或我想要的任何值?
谢谢
您可以使用 useBnIdle
自定义挂钩进行用户空闲检测。您还可以使用 startTimer
函数
重新启动计时器
npm i use-bn-idle
您可以使用startTimer
函数来启动用户空闲检测,它接受秒作为参数。 useBnIdle 需要一个箭头函数作为参数,如果用户在指定时间内空闲,该函数将执行。您可以在该函数中编写您的逻辑来显示模态。
下面的例子有重启按钮,点击它我们可以再次触发 startTimer 秒。它将重新启动用户空闲检测。
import {useBnIdle} from 'use-bn-idle';
const App = () => {
const [startTimer, stopTimer] = useBnIdle(() => {
//Will execute if the user is idle for a certain period of time.
//You can write logic like showing popup or log out the user.
console.log('Expired: Session Timeout');
})
useEffect(() => {
// start the user idle detection
startTimer(60); //passed 60 seconds as argument.
})
const restartTimer = () => {
startTimer(30)
}
return <div>
<button onClick={stopTimer}>Stop Detection</button>
<button onClick={restartTimer}>Restart Timer</button>
</div>
}
我使用 react-idle-timer
创建了一个会话超时,它在第一次时运行良好,但是当我在模态警告中单击“继续会话”时,它不会将超时重置为原始设置(本例中为 30 秒)。单击继续会话后,它会每 5 秒打开一次警告模式。
SessionTimeout.js
import React, { useState, useRef } from "react";
import IdleTimer from "react-idle-timer";
import { useDispatch } from "react-redux";
import { bindActionCreators } from "redux";
import { actionCreators } from '../state/index';
import { useHistory } from "react-router-dom";
import { useSelector } from "react-redux";
import SessionTimeoutDialog from './SessionTimeoutDialog';
let countdownInterval;
let timeout = 1000 * 30 * 1;
const SessionTimeout = () => {
const idleTimer = useRef(null);
const history = useHistory();
const login = useSelector((state) => state.login); // this is just to see if a user is logged
const dispatch = useDispatch();
const { logout } = bindActionCreators(actionCreators, dispatch); // this is to logout
const [timeoutModalOpen, setTimeoutModalOpen] = useState(false);
const [timeoutCountdown, setTimeoutCountdown] = useState(0);
const onActive = () => {
// timer reset automatically.
if (!timeoutModalOpen) {
clearSessionInterval();
clearSessionTimeout();
}
};
const onIdle = () => {
const delay = 1000 * 5;
if(login.logged && !timeoutModalOpen) {
timeout = setTimeout(() => {
let countDown = 60;
setTimeoutModalOpen(true);
setTimeoutCountdown(countDown);
countdownInterval = setInterval(() => {
if (countDown > 0) {
setTimeoutCountdown(--countDown);
} else {
handleLogout();
}
}, 1000);
}, delay);
}
};
const clearSessionTimeout = () => {
clearTimeout(timeout);
};
const clearSessionInterval = () => {
clearInterval(countdownInterval);
};
const handleLogout = () => {
setTimeoutModalOpen(false);
clearSessionInterval();
clearSessionTimeout();
logout();
history.push("/login");
};
const handleContinue = () => {
setTimeoutModalOpen(false);
clearSessionInterval();
clearSessionTimeout();
};
return (
<>
<IdleTimer
ref={idleTimer}
onActive={onActive}
onIdle={onIdle}
debounce={250}
timeout={timeout}
/>
<SessionTimeoutDialog
countdown={timeoutCountdown}
onContinue={handleContinue}
onLogout={handleLogout}
open={timeoutModalOpen}
/>
</>
);
};
export default SessionTimeout;
这是我的模态(对话框)。 SessionTimeoutDialog.jsx
import React from "react";
import * as PropTypes from "prop-types";
import {
Dialog,
DialogTitle,
DialogContent,
DialogActions,
Button,
Typography,
makeStyles,
Slide
} from "@material-ui/core";
import clsx from "clsx";
import red from "@material-ui/core/colors/red";
const useStyles = makeStyles(() => ({
dialog: {
borderRadius: 0
},
button: {
borderRadius: 0,
textTransform: "none",
padding: 5
},
logout: {
color: "#fff",
backgroundColor: red[500],
"&:hover": {
backgroundColor: red[700]
}
},
countdown: {
color: red[700]
}
}));
const Transition = React.forwardRef(function Transition(props,ref) {
return <Slide direction="up" ref={ref} {...props} />;
});
export default function SessionTimeoutDialog({
open,
countdown,
onLogout,
onContinue
}) {
const classes = useStyles();
return (
<Dialog
open={open}
aria-labelledby="session-timeout-dialog"
aria-describedby="session-timeout-dialog"
classes={{ paper: classes.dialog }}
TransitionComponent={Transition}
>
<DialogTitle id="session-timeout-dialog-title">
Session Timeout
</DialogTitle>
<DialogContent>
<Typography variant="body2">
The current session is about to expire in{" "}
<span className={classes.countdown}>{countdown}</span> seconds.
</Typography>
<Typography variant="body2">{`Would you like to continue the session?`}</Typography>
</DialogContent>
<DialogActions>
<Button
onClick={onLogout}
variant="contained"
className={clsx(classes.logout, classes.button)}
>
Logout
</Button>
<Button
onClick={onContinue}
color="primary"
variant="contained"
className={classes.button}
>
Continue Session
</Button>
</DialogActions>
</Dialog>
);
}
SessionTimeoutDialog.propTypes = {
/**
* indicator whether the dialog is open/close
*/
open: PropTypes.bool.isRequired,
/**
* the countdown timer.
*/
countdown: PropTypes.number.isRequired,
/**
* callback function to handle closing action
*/
onLogout: PropTypes.func.isRequired,
/**
* callback function to handle confirm action.
*/
onContinue: PropTypes.func.isRequired
};
这是一个沙箱示例:https://codesandbox.io/s/festive-dust-dzt1t
单击“继续会话”后如何将超时设置回默认的 30 秒或我想要的任何值?
谢谢
您可以使用 useBnIdle
自定义挂钩进行用户空闲检测。您还可以使用 startTimer
函数
npm i use-bn-idle
您可以使用startTimer
函数来启动用户空闲检测,它接受秒作为参数。 useBnIdle 需要一个箭头函数作为参数,如果用户在指定时间内空闲,该函数将执行。您可以在该函数中编写您的逻辑来显示模态。
下面的例子有重启按钮,点击它我们可以再次触发 startTimer 秒。它将重新启动用户空闲检测。
import {useBnIdle} from 'use-bn-idle';
const App = () => {
const [startTimer, stopTimer] = useBnIdle(() => {
//Will execute if the user is idle for a certain period of time.
//You can write logic like showing popup or log out the user.
console.log('Expired: Session Timeout');
})
useEffect(() => {
// start the user idle detection
startTimer(60); //passed 60 seconds as argument.
})
const restartTimer = () => {
startTimer(30)
}
return <div>
<button onClick={stopTimer}>Stop Detection</button>
<button onClick={restartTimer}>Restart Timer</button>
</div>
}