diff --git a/packages/material-ui/src/Snackbar/Snackbar.js b/packages/material-ui/src/Snackbar/Snackbar.js
index 6693a2868ba3c4..ef3e08806e0eb6 100644
--- a/packages/material-ui/src/Snackbar/Snackbar.js
+++ b/packages/material-ui/src/Snackbar/Snackbar.js
@@ -4,6 +4,7 @@ import clsx from 'clsx';
import withStyles from '../styles/withStyles';
import { duration } from '../styles/transitions';
import ClickAwayListener from '../ClickAwayListener';
+import useEventCallback from '../utils/useEventCallback';
import capitalize from '../utils/capitalize';
import createChainedFunction from '../utils/createChainedFunction';
import Grow from '../Grow';
@@ -129,38 +130,30 @@ const Snackbar = React.forwardRef(function Snackbar(props, ref) {
const timerAutoHide = React.useRef();
const [exited, setExited] = React.useState(true);
- // Timer that controls delay before snackbar auto hides
- const setAutoHideTimer = React.useCallback(
- autoHideDurationParam => {
- const autoHideDurationBefore =
- autoHideDurationParam != null ? autoHideDurationParam : autoHideDuration;
+ const handleClose = useEventCallback((...args) => {
+ onClose(...args);
+ });
- if (!onClose || autoHideDurationBefore == null) {
- return;
- }
+ const setAutoHideTimer = useEventCallback(autoHideDurationParam => {
+ if (!handleClose || autoHideDurationParam == null) {
+ return;
+ }
- clearTimeout(timerAutoHide.current);
- timerAutoHide.current = setTimeout(() => {
- const autoHideDurationAfter =
- autoHideDurationParam != null ? autoHideDurationParam : autoHideDuration;
- if (!onClose || autoHideDurationAfter == null) {
- return;
- }
- onClose(null, 'timeout');
- }, autoHideDurationBefore);
- },
- [autoHideDuration, onClose],
- );
+ clearTimeout(timerAutoHide.current);
+ timerAutoHide.current = setTimeout(() => {
+ handleClose(null, 'timeout');
+ }, autoHideDurationParam);
+ });
React.useEffect(() => {
if (open) {
- setAutoHideTimer();
+ setAutoHideTimer(autoHideDuration);
}
return () => {
clearTimeout(timerAutoHide.current);
};
- }, [open, setAutoHideTimer]);
+ }, [open, autoHideDuration, setAutoHideTimer]);
// Pause the timer when the user is interacting with the Snackbar
// or when the user hide the window.
@@ -172,11 +165,7 @@ const Snackbar = React.forwardRef(function Snackbar(props, ref) {
// or when the window is shown back.
const handleResume = React.useCallback(() => {
if (autoHideDuration != null) {
- if (resumeHideDuration != null) {
- setAutoHideTimer(resumeHideDuration);
- return;
- }
- setAutoHideTimer(autoHideDuration * 0.5);
+ setAutoHideTimer(resumeHideDuration != null ? resumeHideDuration : autoHideDuration * 0.5);
}
}, [autoHideDuration, resumeHideDuration, setAutoHideTimer]);
diff --git a/packages/material-ui/src/Snackbar/Snackbar.test.js b/packages/material-ui/src/Snackbar/Snackbar.test.js
index 1d84fe249b1237..a5c276015e79ed 100644
--- a/packages/material-ui/src/Snackbar/Snackbar.test.js
+++ b/packages/material-ui/src/Snackbar/Snackbar.test.js
@@ -1,7 +1,8 @@
import React from 'react';
-import { assert } from 'chai';
+import { expect, assert } from 'chai';
import { spy, useFakeTimers } from 'sinon';
import { createMount, getClasses } from '@material-ui/core/test-utils';
+import { createClientRender } from 'test/utils/createClientRender';
import describeConformance from '../test-utils/describeConformance';
import Snackbar from './Snackbar';
import Grow from '../Grow';
@@ -9,6 +10,7 @@ import Grow from '../Grow';
describe('', () => {
let mount;
let classes;
+ const render = createClientRender({ strict: false });
before(() => {
classes = getClasses();
@@ -130,6 +132,27 @@ describe('', () => {
assert.deepEqual(handleClose.args[0], [null, 'timeout']);
});
+ it('calls onClose at timeout even if the prop changes', () => {
+ const handleClose1 = spy();
+ const handleClose2 = spy();
+ const autoHideDuration = 2e3;
+ const { setProps } = render(
+ ,
+ );
+
+ setProps({ open: true });
+ clock.tick(autoHideDuration / 2);
+ setProps({ open: true, onClose: handleClose2 });
+ clock.tick(autoHideDuration / 2);
+ expect(handleClose1.callCount).to.equal(0);
+ expect(handleClose2.callCount).to.equal(1);
+ });
+
it('should not call onClose when the autoHideDuration is reset', () => {
const handleClose = spy();
const autoHideDuration = 2e3;