css - 使用材质 UI 时动画未触发
问题描述
向我现有的应用程序添加材质 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
解决方案
我已经充分隔离了这一点,以确信这不是Material-UI 的问题,而是用于过渡动画的方法的脆弱性。
要打破它,我所要做的就是包含一个在安装时立即重新渲染的组件(在componentDidMount
或中useLayoutEffect
)。这是TransitionGroup 所做的事情,并且TransitionGroup
被TouchRipple使用,ButtonBase
它被几个 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 所做的那样)。
我可以通过在 中调用mountStyle
via来使您的代码正常工作,但我不能保证此 hack 在其他情况下(取决于模式中的内容)或不同的浏览器不会出现问题,我会改为推荐重新设计转换以管理进入/退出状态。这是我的hack的工作版本: https ://codesandbox.io/s/mui-animation-issue-505rj 。setTimeout
useEffect
react-transition-group
setTimeout
推荐阅读
- node.js - AWS v2 和 v4 签名 URL
- ruby-on-rails - Rails minitest 在 has_many 验证中失败
- android - 如何基于 Xamarin 表单中的当前页面广播消息
- react-native - 使用 expo 字体加载字体的问题
- wpf - 如何在 WPF 的 XAML 布局中实现同一级别的 2 个控制?
- android - 如何在 Firebase 监控工具中获取屏幕渲染跟踪?
- c# - 为什么通过构造函数和 char[] 创建的字符串是实习生的?
- google-play - Android 发布的应用未在搜索中显示
- r - 删除不需要的空格后,使用来自 col X 或 Y 的值创建 col Z
- javascript - 使用 MySQL 处理查询时无法发送正确的响应