Анимация не запускается при использовании пользовательского интерфейса материала - PullRequest
1 голос
/ 15 октября 2019

Я столкнулся с проблемой при добавлении пользовательского интерфейса материала в мое уже существующее приложение. По сути, происходит то, что, когда я добавляю компоненты пользовательского интерфейса материала в мои модалы, входящая анимация модала не срабатывает. Уменьшение UI материала до 1.0.0 или удаление всех компонентов MUI решает проблему. Кроме того, использование любой другой библиотеки пользовательского интерфейса не вызывает этой проблемы.

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 Ответ

1 голос
/ 16 октября 2019

Я выделил это достаточно, чтобы убедиться, что не проблема с 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;

Edit MUI Animation Issue

В приведенном выше примере, который все еще воспроизводитВаша проблема: компоненты Material-UI не используются.

Я полагаю, что повторный рендеринг дочернего элемента влияет (задерживает) время, когда браузер впервые пытается нарисовать модальное изображение и вызывает браузерне распознавать, что произошел переход, когда вы вызываете mountStyle (то есть ведете себя так же, как если бы вы изначально использовали стили «монтирования», а не распознавали переход от стилей по умолчанию к стилям монтирования). Хитрость в правильной настройке времени в React для гарантии того, что браузер выполняет переход, является причиной, по которой люди обычно используют response-transition-group , чтобы помочь с этим (как это делает Material-UI).

Мне удалось заставить ваш код работать, позвонив по номеру mountStyle через setTimeout в useEffect, но я не могу гарантировать, что этот хак не будет иметь проблем в других случаях (в зависимости от того, что находится вмодальные) или другие браузеры, и я бы вместо этого рекомендовал переработать переход, чтобы react-transition-group управлял входящим / выходящим состояниями. Вот рабочая версия с моим setTimeout хаком: https://codesandbox.io/s/mui-animation-issue-505rj.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...