【问题标题】:Animation not triggering when using material UI使用材质 UI 时动画未触发
【发布时间】:2020-02-12 07:25:51
【问题描述】:

向我现有的应用程序添加材质 UI 时遇到问题。基本上发生的情况是,当我将材质 UI 组件添加到我的模态框时,不会触发模态框的进入动画。将材质 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

【问题讨论】:

  • 如果你在按钮上使用disableRipple 属性,它可以正常工作:codesandbox.io/s/mui-animation-issue-ckzgb。我今天不能花更多的时间在这上面,但是如果我们能找出按钮的涟漪有什么副作用,我可以帮助它在 GitHub 中被接受为一个问题。我建议尝试进一步简化你的复制——如果你可以只使用直接的 CSS 类并消除对样式组件的依赖,它将简化对根本原因的追踪。
  • 我把它隔离得更远了。如果我在模态中包含来自react-transition-groupTransitionGroup,这足以导致不良行为(TouchRipple 利用TransitionGroup):codesandbox.io/s/mui-animation-issue-q4bbv

标签: css reactjs material-ui


【解决方案1】:

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

我所要做的就是包含一个在安装时立即重新渲染的组件(在componentDidMountuseLayoutEffect 中)。这是 TransitionGroup doesTransitionGroupused by TouchRippleButtonBase 使用的东西,它被几个 Material-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;

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

我相信子元素的重新渲染会影响(延迟)浏览器首次尝试绘制模式的时间,并导致浏览器在您调用 mountStyle (即行为与您最初使用“安装”样式时的行为相同,而不是识别从默认样式到安装样式的过渡)。在 React 中正确设置此时间以确保浏览器执行转换的技巧是人们通常使用 react-transition-group 来帮助解决此问题的原因(就像 Material-UI 所做的那样)。

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

【讨论】:

  • 哦,知道这真是太酷了!我不确定如何避免这个问题。所以基本上只要动画开始,模态就会重新渲染,因此它会重置动画。您建议如何处理这个问题?
  • @ThePHPAddicted 请参阅我答案末尾的补充内容。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-01-12
  • 2019-11-25
  • 1970-01-01
  • 2017-11-06
  • 1970-01-01
相关资源
最近更新 更多