使用材质UI时不会触发动画

时间:2019-10-15 15:01:07

标签: css reactjs material-ui

将实质性UI添加到我现有的应用程序时遇到问题。基本上发生的事情是,当我向模态中添加材质UI组件时,模态的输入动画不会触发。将Material UI降级为1.0.0或删除所有MUI组件即可解决此问题。另外,使用任何其他UI库也不会导致此问题。

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;

Test组件包含任何类型的MUI组件时,输入的动画不会触发。控制台中没有错误。 显然,在我的代码中确实触发了此问题,因为我已经在他们的github上打开了一个问题,他们说这与他们的库无关:https://github.com/mui-org/material-ui/issues/17888

1 个答案:

答案 0 :(得分:1)

我已经充分隔离了这一点,以确信它不是Material-UI的问题,而是过渡动画所使用方法的脆弱性。

要打破它,我要做的就是添加一个可以在挂载时立即重新渲染的组件(在componentDidMountuseLayoutEffect中)。 TransitionGroup doesTransitionGroupused by TouchRippleButtonBase使用了{Materials-UI组件,例如按钮。

Test组件更改为以下内容足以引起不良行为:

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

在上面的示例仍然可以重现您的问题的情况下,没有使用Material-UI组件。

我认为子元素的重新渲染会影响(延迟)浏览器首次尝试绘制模式时的时间,并导致浏览器在您调用{{1}时无法识别发生了过渡}(即,与最初使用“ mount”样式一样,而不是识别从默认样式到Mount样式的转换)。在React中正确设置此时间以确保浏览器进行转换的棘手问题是人们通常使用react-transition-group来解决此问题的原因(就像Material-UI一样)。

我可以通过在mountStyle中通过mountStyle调用setTimeout来使您的代码正常工作,但是我不能保证在其他情况下该hack不会出现问题(取决于模式中的内容)或不同的浏览器,我建议改写转换,以让useEffect管理进入/退出状态。这是带有我的react-transition-group技巧的工作版本:https://codesandbox.io/s/mui-animation-issue-505rj