Почему Enter-анимация не запускается при монтировании новых компонентов страницы - PullRequest
1 голос
/ 03 июня 2019

В этом примере кода выходной переход работает, а входной переход - нет. Мне любопытно, если я подхожу к этому правильно, если это ошибка с styled-компонентами.

Цель состоит в том, чтобы анимировать до 50% от экрана при выходе и анимировать от 100% до экрана при вводе. Я установил непрозрачность на 50%, чтобы можно было постоянно видеть оба элемента div.

Я бы предпочел использовать Transition вместо CSSTransition, поскольку я хотел бы просто использовать стилевые компоненты вместо смешивания в обычных таблицах стилей.

Пример кода: https://codesandbox.io/s/sweet-mcnulty-dbptv

Состояния анимации при выходе (см. Консоль в CodeSandbox):

  1. введено - установить начальное положение и отключить переходы
  2. выход - установить целевую позицию и разрешить переходы
  3. выход - не имеет значения, поскольку компонент отключен с помощью реакции-маршрутизатора

ПРИМЕЧАНИЕ: это (выходной переход) работает хорошо.

Состояния анимации при входе (см. Консоль в CodeSandbox):

  1. выход - установить исходное положение и отключить переходы
  2. ввод - установить целевую позицию и разрешить переходы
  3. 1029 * вошел *

Это (входной переход) вообще не анимируется. Большая разница между входом и выходом состоит в том, что при выходе компонент уже смонтирован, а на входе он смонтирован непосредственно перед тем, как должна произойти анимация. Мой рабочий тезис заключается в том, что styled-component не передает оба обновления CSS (шаг 1 и 2) в DOM по отдельности, и поэтому браузер не запускает переход. Но я этого не знаю, во всяком случае, это происходит только в том случае, если вы монтируете перед самым переходом.

Есть идеи?

Пример полного кода (аналогично https://codesandbox.io/s/sweet-mcnulty-dbptv):

import React from "react";
import ReactDOM from "react-dom";
import styled from "styled-components";
import { BrowserRouter as Router, Route, Switch, Link } from "react-router-dom";
import { TransitionGroup, Transition } from "react-transition-group";

const Nav = styled.nav`
  display: flex;
  justify-content: space-around;
  align-items: center;
  height: 80px;
`;

const Page = styled.div`
  background: white;
  display: flex;
  justify-content: center;
  align-items: center;
  will-change: transform;
  position: fixed;
  top: 80px;
  bottom: 0;
  left: 0;
  right: 0;
  background: ${props => (props.backgroundColor === "gray" ? "#eee" : "#efe")};
  opacity: 0.5;

  transform: ${props => {
    // Details page is green
    if (props.backgroundColor === "green") {
      // console.log(new Date().getTime(), 'Details page (css):      ', props.transitionState);
    }

    switch (props.transitionState) {
      case "entering":
        return "translateX(0)";

      case "entered":
        return "translateX(0)";

      case "exiting":
        return "translateX(-50%)";

      case "exited":
        return "translateX(100%)";

      default:
        throw new Error("This should never happen");
    }
  }};

  transition: ${props => {
    switch (props.transitionState) {
      case "entering":
        return "transform 1000ms cubic-bezier(0, 0, 0, 1)";

      case "entered":
        return "none";

      case "exiting":
        return "transform 1000ms cubic-bezier(0, 0, 0, 1)";

      case "exited":
        return "none";

      default:
        throw new Error("This should never happen");
    }
  }};
`;

const HomePage = props => {
  return (
    <Page backgroundColor="gray" transitionState={props.transitionState}>
      Home page!
    </Page>
  );
};

const DetailsPage = props => {
  console.log(new Date().getTime(), 'Details page (component):', props.transitionState);

  return (
    <Page backgroundColor="green" transitionState={props.transitionState}>
      Details page!
    </Page>
  );
};

function App() {
  return (
    <Router>
      <Nav>
        <Link to="/">Home</Link>
        <Link to="/details">Details</Link>
      </Nav>
      <Route
        render={({ location }) => {
          return (
            <TransitionGroup component={null}>
              <Transition key={location.pathname} timeout={1000}>
                {transitionState => {
                  return (
                    <Switch location={location}>
                      <Route
                        exact
                        path="/"
                        render={() => (
                          <HomePage transitionState={transitionState} />
                        )}
                      />
                      <Route
                        exact
                        path="/details"
                        render={() => (
                          <DetailsPage transitionState={transitionState} />
                        )}
                      />
                    </Switch>
                  );
                }}
              </Transition>
            </TransitionGroup>
          );
        }}
      />
    </Router>
  );
}

const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);

1 Ответ

0 голосов
/ 04 июня 2019

Вот способ обойти это, но он требует использования CSSTransition. Это по-прежнему не объясняет, почему пример из исходного вопроса не работает.

https://codesandbox.io/s/page-transition-with-csstransition-working-emudw

import React from "react";
import ReactDOM from "react-dom";
import styled from "styled-components";
import { BrowserRouter as Router, Route, Switch, Link } from "react-router-dom";
import { TransitionGroup, CSSTransition } from "react-transition-group";

const Nav = styled.nav`
  display: flex;
  justify-content: space-around;
  align-items: center;
  height: 80px;
`;

const Page = styled.div`
  background: white;
  display: flex;
  justify-content: center;
  align-items: center;
  will-change: transform;
  position: fixed;
  top: 80px;
  bottom: 0;
  left: 0;
  right: 0;
  background: ${props => (props.backgroundColor === "gray" ? "#eee" : "#efe")};
  opacity: 0.5;

  &.page-transition-enter {
    transform: translateX(100%);
    transition: none;
  }

  &.page-transition-enter-active {
    transform: translateX(0);
    transition: transform 1000ms cubic-bezier(0, 0, 0, 1);
  }

  &.page-transition-exit {
    transform: translateX(0);
    transition: none;
  }

  &.page-transition-exit-active {
    transform: translateX(-50%);
    transition: transform 1000ms cubic-bezier(0, 0, 0, 1);
  }
`;

const HomePage = props => {
  return <Page backgroundColor="gray">Home page!</Page>;
};

const DetailsPage = props => {
  return <Page backgroundColor="green">Details page!</Page>;
};

function App() {
  return (
    <Router>
      <Nav>
        <Link to="/">Home</Link>
        <Link to="/details">Details</Link>
      </Nav>
      <Route
        render={({ location }) => {
          return (
            <TransitionGroup component={null}>
              <CSSTransition
                key={location.pathname}
                timeout={1000}
                classNames="page-transition"
              >
                <Switch location={location}>
                  <Route exact path="/" render={() => <HomePage />} />
                  <Route exact path="/details" render={() => <DetailsPage />} />
                </Switch>
              </CSSTransition>
            </TransitionGroup>
          );
        }}
      />
    </Router>
  );
}

const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
...