2

I encountered an issue when adding material UI to my already existing application. Basically what's happening is that when I add material UI components to my modals, the entering animation of the modal does not trigger. Downgrading material UI to 1.0.0 or removing all MUI components solves the issue. Also, using any other UI library does not cause this issue.

https://codesandbox.io/s/mui-animation-issue-mgph3

import React, { useState, useEffect } from "react";
import styled from "styled-components";
import Test from "./Test";
const Overlay = styled.div`
 position: absolute;
 top: 0;
 left: 0;
 bottom: 0;
 right: 0;
 z-index: 10000;
`;
const Modal = styled.div`
 position: absolute;
 display: flex;
 flex-direction: column;
 justify-content: center;
 width: 100px;
 height: 100px;
 align-items: center;
 background: white;
`;
const modalsComponentLookupTable = {
 Test
};
const ModalContainer = ({ setModals, children }) => {
 const [modalStyle, setModalStyle] = useState({
 opacity: 0,
 transition: "opacity 2000ms",
 willChange: "opacity",
 transitionTimingFunction: "cubic-bezier(0.165, 0.840, 0.440, 1.000)"
 });
 const [bgStyle, setBgStyle] = useState({
 background: "rgba(0, 0, 0, 1)",
 willChange: "opacity",
 transition: "opacity 2000ms cubic-bezier(0.165, 0.840, 0.440, 1.000)",
 opacity: 0
 });
 const unMountStyle = () => {
 // css for unmount animation
 setModalStyle({
 opacity: 0,
 transition: "opacity 2200ms",
 willChange: "opacity",
 transitionTimingFunction: "cubic-bezier(0.165, 0.840, 0.440, 1.000)"
 });
 setBgStyle({
 background: "rgba(0, 0, 0, 1)",
 willChange: "opacity",
 transition: "opacity 2200ms cubic-bezier(0.165, 0.840, 0.440, 1.000)",
 opacity: 0
 });
 };
 const mountStyle = () => {
 // css for mount animation
 setModalStyle({
 opacity: 1,
 transition: "opacity: 2000ms",
 willChange: "opacity",
 transitionTimingFunction: "cubic-bezier(0.165, 0.840, 0.440, 1.000)"
 });
 setBgStyle({
 willChange: "opacity",
 opacity: 1,
 background: "rgba(0, 0, 0, 1)",
 transition: "opacity 2000ms cubic-bezier(0.165, 0.840, 0.440, 1.000)"
 });
 };
 useEffect(() => {
 mountStyle();
 }, []);
 const back = e => {
 e.stopPropagation();
 unMountStyle();
 setTimeout(() => setModals([]), 2200);
 };
 return (
 <Overlay onClick={back} style={bgStyle}>
 <Modal style={modalStyle}>{children}</Modal>
 </Overlay>
 );
};
const ModalsManager = ({ modals, setModals }) => {
 const renderedModals = modals.map(modalDescription => {
 const ModalComponent = modalsComponentLookupTable[modalDescription];
 return (
 <ModalContainer setModals={setModals}>
 <ModalComponent />
 </ModalContainer>
 );
 });
 return <span>{renderedModals}</span>;
};
export default ModalsManager;

When the Test component contains any kind of MUI components, the entering animation doesn't trigger. No error in the console. Apparently it's something in my code that does trigger this issue since I already opened an issue on their github and they said it's not an issue with their library: https://github.com/mui-org/material-ui/issues/17888

asked Oct 15, 2019 at 15:01
2
  • If you use the disableRipple prop on the buttons, it works fine: codesandbox.io/s/mui-animation-issue-ckzgb. I can't spend more time on it today, but if we can isolate what about the ripple of the buttons is having this side-effect, I can help get it accepted as an issue in GitHub. I recommend trying to simplify your reproduction even further -- if you can use just straight CSS classes and remove the dependency on styled-components, it would simplify tracking down the root cause. Commented Oct 15, 2019 at 19:04
  • I have isolated it a little further. If I include TransitionGroup from react-transition-group in the modal, that is sufficient to cause the bad behavior (TouchRipple leverages TransitionGroup): codesandbox.io/s/mui-animation-issue-q4bbv Commented Oct 16, 2019 at 1:25

1 Answer 1

5

I have isolated this sufficiently to be convinced that it is not a problem with Material-UI, but rather a brittleness in the approach used for your transition animation.

All I have to do to break it is to include a component that immediately re-renders on mount (either in componentDidMount or useLayoutEffect). This is something that TransitionGroup does and TransitionGroup is used by TouchRipple which is used by ButtonBase which is used by several Material-UI components such as button.

Changing your Test component to the following was sufficient to cause the bad behavior:

import React from "react";
const RerenderOnMount = () => {
 const [, setMyState] = React.useState(false);
 React.useLayoutEffect(() => {
 setMyState(true);
 }, []);
 return null;
};
const Test = () => {
 return (
 <div
 css={`
 height: 100px;
 width: 100px;
 z-index: 5;
 `}
 onClick={e => e.stopPropagation()}
 >
 <div>
 Test
 <RerenderOnMount />
 </div>
 </div>
 );
};
export default Test;

Edit MUI Animation Issue

In the example above which still reproduces your problem, no Material-UI components are being used.

I believe the re-render of the child element is impacting (delaying) the timing of when the browser first tries to paint the modal and is causing the browser to not recognize that a transition has occurred when you call mountStyle (i.e. behaving the same as if you had used the "mount" styles initially rather than recognizing a transition from the default styles to the mount styles). The trickiness in getting this timing correct in React to ensure the browser does a transition is the reason why people typically use react-transition-group to help with this (as Material-UI does).

I was able to get your code to work by calling mountStyle via setTimeout within the useEffect, but I can't guarantee that this hack won't have issues in other cases (depending on what is in the modal) or different browsers, and I would instead recommend reworking the transition to let react-transition-group manage the entering/exiting states. Here's the working version with my setTimeout hack: https://codesandbox.io/s/mui-animation-issue-505rj.

answered Oct 16, 2019 at 1:59
Sign up to request clarification or add additional context in comments.

2 Comments

Oh that's really cool to know! I'm not sure how to avoid that issue though. So basically as soon as the animation starts, the modal rerenders and so it resets the animation. How would you suggest approaching this?
@ThePHPAddicted See the additions at the end of my answer.

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.