简体   繁体   中英

"Can't perform a React state update on an unmounted component" when i try to change state in useEffect()

I have a material drawer component that, when the component mounts, needs to check the local storage and get the logged in user, and then put the name of the user in the template.

This is my component:

const PersistentDrawer = () => {

  const [userLogged, setUserLogged] = useState({});
  useEffect(() => {
    setUserLogged(JSON.parse(localStorage.getItem('currentUser')))
        // eslint-disable-next-line react-hooks/exhaustive-deps
    },[])
  const classes = drawerStyles();
  const theme = useTheme();
  const [open, setOpen] = useState(false);

  const handleDrawerOpen = () => {
    setOpen(true);
  };

  const handleDrawerClose = () => {
    setOpen(false);
  };

  return (
    <div className={classes.root}>
        <CssBaseline />
        <AppBar
            position="fixed"
            className={clsx(classes.appBar, {
            [classes.appBarShift]: open,
            })}
        >        
            <Toolbar>
            <IconButton
                color="inherit"
                aria-label="open drawer"
                onClick={handleDrawerOpen}
                edge="start"
                className={clsx(classes.menuButton, open && classes.hide)}
            >
                <MenuIcon />
            </IconButton>
            <Typography variant="h6" noWrap>
                Persistent drawer
            </Typography>
            </Toolbar>
        </AppBar>
        <Drawer
            className={classes.drawer}
            variant="persistent"
            anchor="left"
            open={open}
            classes={{
            paper: classes.drawerPaper,
            }}
        >
            <img className={classes.logo} alt="Incca Sistemas" src="/assets/logo-incca.png"></img>          
            <div className={classes.drawerHeader}>
        <Typography component="h6">{userLogged.login}</Typography>
            <IconButton onClick={handleDrawerClose}>
                {theme.direction === 'ltr' ? <ChevronLeftIcon /> : <ChevronRightIcon />}
            </IconButton>
            </div>
            <Divider />
            <List>
            {['Inbox', 'Starred', 'Send email', 'Drafts'].map((text, index) => (
                <ListItem button key={text}>
                <ListItemIcon>{index % 2 === 0 ? <InboxIcon /> : <MailIcon />}</ListItemIcon>
                <ListItemText primary={text} />
                </ListItem>
            ))}
            </List>
            <Divider />
        </Drawer>
        <main
            className={clsx(classes.content, {
            [classes.contentShift]: open,
            })}
        >
        </main>
    </div>
  );
}

export default PersistentDrawer

I'm receiving:

Can't perform a React state update on an unmounted component. This is a no-op, but it indicates a memory leak in your application. To fix, cancel all subscriptions and asynchronous tasks in a useEffect cleanup function.

How I can fix this?

Change your useEffect to be as follows:

useEffect(() => {
  let neverMind = false;

  const currentUser = JSON.parse(localStorage.getItem('currentUser'))

  if(!neverMind) setUserLogged(currentUser)
  return () => ( neverMind = true);
},[])

Somehow your component is being unmounted, but even though it is unmounted - you are still trying to update its state. To avoid this, set a flag that will let you know when the component is unmounted (in the function being returned) and only update the state if the flag has not changed.

For another example of how the "cleanup function" is used, see the React docs - https://reactjs.org/docs/hooks-effect.html#example-using-hooks-1

Here is a link to Dan Abramov's answer to this question - https://github.com/facebook/react/issues/14369#issuecomment-468267798

Can't perform a React state update on an unmounted component.

This error occurs when an attempt is made to change a component that does not exist yet.

This is very often a result of parallel initializations (async) of components.

For Example: Suppose that two components A, B are both initialized asynchronously in lines 1, 2. In line 3, if Component A tries to update Component B, then there is a likelihood that the component B (line2) did not get created by the time line 3 (update to B) got executed.

In such a case, the above error will be reported.

How to fix? Identify and change the async code blocks or functions to make sure that no update is attempted on a component before it gets created.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM