Material-ui dialog flickering when using redux for open state

Viewed 2524

I am trying to move the open state for material-ui dialog to redux to prevent it from closing when a rerender occurs, but i having trouble with the dialog when a rerender occurs. Although the state is saved in redux and the dialog does stay open whenever a rerender occurs the open state stays open but the dialog does show the open animation (fading in) which is kinda annoying.

Students.js (parent component of the modal)

const Students = ({
    app: { studentsPage: { savedAddDialogOpen }},
  setStudentsPageAddDialogOpen}) => {

    // Create the local states
    const [dialogOpen, setDialogOpen] = React.useState(savedAddDialogOpen);
    const dialogOpenRef = React.useRef(savedAddDialogOpen);

    // Change redux dialog open
    const setReduxDialogState = () => {
      setStudentsPageAddDialogOpen(dialogOpenRef.current, savedAddDialogOpen);
    };

    // Open add student dialog
    const dialogClickOpen = () => {
      setDialogOpen(true);
      dialogOpenRef.current = true;
      setTimeout(() => setReduxDialogState(), 300);
    };

    // Close add student dialog
    const dialogClose = () => {
      setDialogOpen(false);
      dialogOpenRef.current = false;
      setTimeout(() => setReduxDialogState(), 300);
    };

    return (
      <Container>
        {/* Add student modal */}
        <AddStudentModal dialogOpen={dialogOpen} dialogClose={dialogClose} />
      </Container>
    )

}

// Set the state for this component to the global state
const mapStateToProps = (state) => ({
  app: state.app,
});

AddStudentModal.js

const AddStudentModal = ({
    dialogOpen, dialogClose
    }) => {

    return (
      <Dialog
        open={dialogOpen}
      >
        {/* Lots of stuff*/}
        <DialogActions>
          <Button onClick={dialogClose}>
            Close dialog
          </Button>
        </DialogActions>
      </Dialog>
    )
};

I hope this should be sufficient. I tried checking if the open state is actually correct when a rerender occurs and it is correct every time but it looks like the dialog is closed at a rerender no matter what the open state is and only a few ms later actually notices that it should be opened.

Any help would be really appreciated

Edit 1: Found out it has nothing to do with the open state coming from redux, if i use open={true} it still flashes, so probably a problem with material-ui itself?

Edit 2: PrivateRoute.js

const PrivateRoute = ({
  auth: { isAuthenticated, loadingAuth },
  user: { loggedInUser },
  component: Component,
  roles,
  path,
  setLastPrivatePath,
  ...rest
}) => {
  useEffect(() => {
    if (path !== '/dashboard' && path !== '/profile') {
      setLastPrivatePath(path);
    }
    // Prevent any useless errors with net line:
    // eslint-disable-next-line
  }, [path]);

  // If we are loading the user show the preloader
  if (loadingAuth) {
    return <Preloader />;
  }

  // Return the component (depending on authentication)
  return (
    <Route
      {...rest}
      render={props =>
        !isAuthenticated ? (
          <Redirect to="/login" />
        ) : (loggedInUser && roles.some(r => loggedInUser.roles.includes(r))) ||
          roles.includes('any') ? (
          <Component {...props} />
        ) : (
          <NotAuthorized />
        )
      }
    />
  );
};

// Set the state for this component to the global state
const mapStateToProps = state => ({
  auth: state.auth,
  user: state.user
});

1 Answers

I found the problem thanks to @RyanCogswell!

For anyone having the same problem here is the cause for me and the fix:

I was passing components into the Route component like this:

<PrivateRoute
   exact
   path={'/dashboard/students'}
   component={(props) => (
     <Students {...props} selectedIndex={selectedIndexSecondary} />
   )}
   roles={['admin']}
/>

By doing it this way i could pass props through my privateRoute function but this would also happen if you send the component this way in a normal Route component

Solution for me is just moving selectedIndexSecondary to redux and sending the component the normal way it prevented the re-mounting.

So just doing it like this will prevent this from happening.

<PrivateRoute
   exact
   path={'/dashboard/students'}
   component={Students}
   roles={['admin']}
/>

Also this will solve the localstates in your components from resseting to the default value. So for me it fixed two problems!

Related