Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Snackbar] Fix timer restarting when parent component re-render #18361

Merged
merged 3 commits into from Nov 18, 2019
Merged

[Snackbar] Fix timer restarting when parent component re-render #18361

merged 3 commits into from Nov 18, 2019

Conversation

savi2w
Copy link

@savi2w savi2w commented Nov 14, 2019

How can I create tests for this fix?
(Closes #18353)

@mui-pr-bot
Copy link

mui-pr-bot commented Nov 14, 2019

Details of bundle changes.

Comparing: f0bfa93...9bd6e44

bundle Size Change Size Gzip Change Gzip
@material-ui/core[umd] ▼ -34 B (-0.01% ) 310 kB ▼ -9 B (-0.01% ) 89.3 kB
@material-ui/core ▼ -10 B (-0.00% ) 351 kB ▲ +5 B (+0.01% ) 96 kB
Snackbar ▼ -10 B (-0.01% ) 75.8 kB ▼ -1 B (-0.00% ) 23.6 kB
docs.main ▼ -6 B (-0.00% ) 609 kB ▼ -4 B (-0.00% ) 194 kB
@material-ui/lab -- 172 kB -- 51.8 kB
@material-ui/styles -- 50.8 kB -- 15.4 kB
@material-ui/system -- 14.8 kB -- 4.06 kB
AppBar -- 62.4 kB -- 19.6 kB
Autocomplete -- 126 kB -- 40 kB
Avatar -- 61.4 kB -- 19.3 kB
Backdrop -- 66.4 kB -- 20.5 kB
Badge -- 64 kB -- 19.8 kB
BottomNavigation -- 61 kB -- 19.1 kB
BottomNavigationAction -- 74.1 kB -- 23.4 kB
Box -- 69.4 kB -- 21 kB
Breadcrumbs -- 66.6 kB -- 20.9 kB
Button -- 78 kB -- 23.8 kB
ButtonBase -- 72.5 kB -- 22.7 kB
ButtonGroup -- 80.6 kB -- 24.7 kB
Card -- 61.4 kB -- 19.2 kB
CardActionArea -- 73.6 kB -- 23.2 kB
CardActions -- 60.7 kB -- 19 kB
CardContent -- 60.6 kB -- 18.9 kB
CardHeader -- 63.7 kB -- 20 kB
CardMedia -- 61 kB -- 19.1 kB
Checkbox -- 80.4 kB -- 25.2 kB
Chip -- 81.1 kB -- 24.8 kB
CircularProgress -- 62.7 kB -- 19.7 kB
ClickAwayListener -- 3.87 kB -- 1.56 kB
Collapse -- 66.5 kB -- 20.5 kB
colorManipulator -- 3.83 kB -- 1.52 kB
Container -- 61.8 kB -- 19.3 kB
CssBaseline -- 56.2 kB -- 17.6 kB
Dialog -- 81.1 kB -- 25.2 kB
DialogActions -- 60.7 kB -- 19 kB
DialogContent -- 60.8 kB -- 19.1 kB
DialogContentText -- 62.7 kB -- 19.7 kB
DialogTitle -- 62.9 kB -- 19.8 kB
Divider -- 61.2 kB -- 19.2 kB
docs.landing -- 55.8 kB -- 14.3 kB
Drawer -- 82.9 kB -- 25.6 kB
ExpansionPanel -- 69.8 kB -- 21.8 kB
ExpansionPanelActions -- 60.7 kB -- 19 kB
ExpansionPanelDetails -- 60.6 kB -- 18.9 kB
ExpansionPanelSummary -- 76.7 kB -- 24.1 kB
Fab -- 75.4 kB -- 23.4 kB
Fade -- 22.2 kB -- 7.66 kB
FilledInput -- 72.2 kB -- 22.3 kB
FormControl -- 63 kB -- 19.5 kB
FormControlLabel -- 64.1 kB -- 20.1 kB
FormGroup -- 60.6 kB -- 19 kB
FormHelperText -- 61.9 kB -- 19.4 kB
FormLabel -- 62.1 kB -- 19.2 kB
Grid -- 63.7 kB -- 20 kB
GridList -- 61.1 kB -- 19.2 kB
GridListTile -- 62.4 kB -- 19.5 kB
GridListTileBar -- 61.8 kB -- 19.4 kB
Grow -- 22.8 kB -- 7.79 kB
Hidden -- 64.6 kB -- 20.2 kB
Icon -- 61.4 kB -- 19.2 kB
IconButton -- 74.7 kB -- 23.3 kB
Input -- 71.1 kB -- 22.1 kB
InputAdornment -- 63.7 kB -- 20.1 kB
InputBase -- 69.2 kB -- 21.7 kB
InputLabel -- 63.9 kB -- 19.9 kB
LinearProgress -- 64 kB -- 19.9 kB
Link -- 65.2 kB -- 20.7 kB
List -- 61 kB -- 19 kB
ListItem -- 75.7 kB -- 23.6 kB
ListItemAvatar -- 60.7 kB -- 19 kB
ListItemIcon -- 60.8 kB -- 19 kB
ListItemSecondaryAction -- 60.6 kB -- 19 kB
ListItemText -- 63.6 kB -- 20 kB
ListSubheader -- 61.4 kB -- 19.3 kB
Menu -- 86.8 kB -- 27.2 kB
MenuItem -- 76.7 kB -- 23.9 kB
MenuList -- 64.6 kB -- 20.2 kB
MobileStepper -- 66.3 kB -- 20.7 kB
Modal -- 14.2 kB -- 4.96 kB
NativeSelect -- 75.4 kB -- 23.7 kB
NoSsr -- 2.19 kB -- 1.03 kB
OutlinedInput -- 72.7 kB -- 22.5 kB
Paper -- 60.9 kB -- 18.9 kB
Popover -- 81.2 kB -- 25 kB
Popper -- 28.6 kB -- 10.2 kB
Portal -- 2.87 kB -- 1.29 kB
Radio -- 81.2 kB -- 25.5 kB
RadioGroup -- 61.9 kB -- 19.3 kB
Rating -- 68.6 kB -- 22 kB
RootRef -- 4.43 kB -- 1.67 kB
Select -- 113 kB -- 33.5 kB
Skeleton -- 61.1 kB -- 19.2 kB
Slide -- 24.3 kB -- 8.27 kB
Slider -- 74.2 kB -- 23.4 kB
SnackbarContent -- 64.3 kB -- 20.2 kB
SpeedDial -- 84.6 kB -- 26.6 kB
SpeedDialAction -- 115 kB -- 36.4 kB
SpeedDialIcon -- 63.2 kB -- 19.8 kB
Step -- 61.2 kB -- 19.2 kB
StepButton -- 80.9 kB -- 25.4 kB
StepConnector -- 61.3 kB -- 19.3 kB
StepContent -- 67.6 kB -- 21.1 kB
StepIcon -- 63.3 kB -- 19.7 kB
StepLabel -- 67.2 kB -- 21.1 kB
Stepper -- 63.4 kB -- 19.9 kB
styles/createMuiTheme -- 15.4 kB -- 5.43 kB
SvgIcon -- 61.7 kB -- 19.2 kB
SwipeableDrawer -- 90.3 kB -- 28 kB
Switch -- 79.7 kB -- 24.8 kB
Tab -- 74.9 kB -- 23.7 kB
Table -- 61.2 kB -- 19.2 kB
TableBody -- 60.7 kB -- 19 kB
TableCell -- 62.7 kB -- 19.7 kB
TableFooter -- 60.7 kB -- 19 kB
TableHead -- 60.7 kB -- 19 kB
TablePagination -- 139 kB -- 40.7 kB
TableRow -- 61.2 kB -- 19.1 kB
TableSortLabel -- 75.9 kB -- 24 kB
Tabs -- 84 kB -- 26.8 kB
TextareaAutosize -- 5.06 kB -- 2.11 kB
TextField -- 121 kB -- 35.5 kB
ToggleButton -- 74.7 kB -- 23.6 kB
ToggleButtonGroup -- 61.8 kB -- 19.4 kB
Toolbar -- 61 kB -- 19.1 kB
Tooltip -- 99.1 kB -- 31.3 kB
TreeItem -- 72.2 kB -- 22.7 kB
TreeView -- 65 kB -- 20.3 kB
Typography -- 62.3 kB -- 19.4 kB
useAutocomplete -- 12.2 kB -- 4.5 kB
useMediaQuery -- 2.49 kB -- 1.05 kB
Zoom -- 22.3 kB -- 7.67 kB

Generated by 🚫 dangerJS against 9bd6e44

@oliviertassinari
Copy link
Member

@weslenng Could you add a test case? Thanks.

@oliviertassinari oliviertassinari added bug 🐛 Something doesn't work component: snackbar This is the name of the generic UI component, not the React module! labels Nov 14, 2019
@savi2w
Copy link
Author

savi2w commented Nov 14, 2019

@oliviertassinari I will try to make a test case, but as I had questioned in PR I don't know exactly how to test this situation. Can you help me?

@oliviertassinari
Copy link
Member

I would recommend to start from the codesandbox reproduction. Convert it to a test case, observe that it fails without the patch. This should do it :).

@savi2w
Copy link
Author

savi2w commented Nov 14, 2019

@oliviertassinari Shouldn't this test work? The logic makes sense to me, but it's not failing (without the patch).

it('should call onClose when timer done after a parent re-render', () => {
  const handleClose = spy();
  const autoHideDuration = 2e3;
  const TestCase = props => (
    <div>
      <div>{props.renderParent ? "Hello" : "World"}</div>
      <Snackbar
        open={props.open}
        onClose={handleClose}
        message="message"
        autoHideDuration={autoHideDuration}
      />
    </div>
  );

  const wrapper = mount(<TestCase />);
  wrapper.setProps({ open: true });
  assert.strictEqual(handleClose.callCount, 0);
  clock.tick(autoHideDuration / 2);
  wrapper.setProps({ renderParent: true });
  clock.tick(autoHideDuration / 2);
  assert.strictEqual(handleClose.callCount, 1);
  assert.deepEqual(handleClose.args[0], [null, 'timeout']);
})

@oliviertassinari
Copy link
Member

oliviertassinari commented Nov 14, 2019

@weslenng The onClose reference needs to change between two renders.

Copy link
Member

@eps1lon eps1lon left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great catch. Declarative timeouts are pretty tricky.

},
[autoHideDuration, onClose],
);
const setAutoHideTimer = useEventCallback(autoHideDurationParam => {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This uses a layout effect internally which is not necessary I believe. Looking at how useInterval is defined I think we can use useEffect or better extract this into a separate useTimeout hook so that it is crystal clear what is responsible for what.

https://overreacted.io/making-setinterval-declarative-with-react-hooks/#just-show-me-the-code

@oliviertassinari oliviertassinari added the PR: needs revision The pull request can't be merged. More details is available on the code review or fails in the CI label Nov 15, 2019
@savi2w
Copy link
Author

savi2w commented Nov 15, 2019

@weslenng The onClose reference needs to change between two renders.

Thanks.

@oliviertassinari The case test is done. In which prop describe do you think it would be semantically correct? I'm between onClose and autoHideDuration, both look right to me

@oliviertassinari
Copy link
Member

@weslenng I would say autoHideDuration.

@oliviertassinari oliviertassinari removed the PR: needs revision The pull request can't be merged. More details is available on the code review or fails in the CI label Nov 16, 2019
Copy link
Member

@oliviertassinari oliviertassinari left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have updated the pull request to also use the latest onClose prop. I have updated the tests to reflect it. I have explored the useTimeout approach, the problem is that it would require to rerender when the timer is pause or resume, it's unclear how we can handle the resumeHideDuration vs autoHideDuration difference down this path. I haven't changed the imperative approach, I think that we can revisit it in the future if it cause a problem. I think that it's good enough to be merged.

@eps1lon eps1lon merged commit 44ded64 into mui:master Nov 18, 2019
@eps1lon
Copy link
Member

eps1lon commented Nov 18, 2019

@weslenng Thanks. Especially for adding a test 👍

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug 🐛 Something doesn't work component: snackbar This is the name of the generic UI component, not the React module!
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[Snackbar] Auto hide timer restarts when parent component re-renders
4 participants