将 ReactCSSTransitionGroup 与样式组件一起使用

Using ReactCSSTransitionGroup with styled-component

我正在使用 styled-components instead of tradition way of css. But I don't know how it can work together with ReactCSSTransitionGroup

基本上,ReactCSSTransitionGroup 在 css 资源中查找某些 class 名称,然后在其整个生命周期中应用于组件。但是,对于 styled-components,没有任何 class 名称,样式直接应用于组件。

我知道我可以选择不使用 ReactCSSTransitionGroup 因为这两种技术看起来不兼容。但是当我只使用 styled-components 时,似乎我无法在卸载组件时呈现任何动画 - 它是纯粹的 css,无法访问组件的生命周期。

如有任何帮助或建议,我们将不胜感激。

像下面这样在 CSS 中尝试驼峰命名法。

.enter {

}
.enterActive { }

在引导 React 应用程序的地方使用 injectGlobal() 样式组件辅助方法。使用这种方法,您可以像使用传统的 CSS.

一样设置任何 CSS 选择器的样式

首先创建一个 JS 文件,使用 CSS 为 react-transition-group 导出模板文字(请注意,我使用的是 v2.1 新的 class 名称语法):

globalCss.js

const globalCss = `
    .transition-classes {
        /* The double class name is to add more specifity */
        /* so that this CSS has preference over the component one. */
        /* Try removing it, you may not need it if properties don't collide */
        /* https://www.styled-components.com/docs/advanced#issues-with-specificity */

        &-enter&-enter {
        }

        &-enter&-enter-active {
        }

        &-exit&-exit {
        }

        &-exit&-exit-active {
        }
    }
`;

export default globalCss;

然后在您的入口点文件上:

index.jsx

import { injectGlobal } from "styled-components";
import globalCss from "./globalCss.js";

injectGlobal`${ globalCss }`; // <-- This will do the trick

ReactDOM.render(
    <Provider store={ Store } >
        <HashRouter >
            <Route path="/" component={ Component1 } />
            <Route path="/" component={ Component2 } />
        </HashRouter>
    </Provider>,
    document.getElementsByClassName("react-app")[0]
);

但是,如果您只是使用 CSS/SASS/Less 为 react-trasition-group 编写 classes,即使您使用样式组件,它也能正常工作。

您可以在 styled-components 中使用 css 变量选择器。像这样:

const Animation = styled(ReactCSSTransitionGroup)`
  ${({ transitionName }) => `.${transitionName}-enter`} {
    opacity: 0;
  }

  ${({transitionName}) => `.${transitionName}-leave`} {
    opacity: 1;
  }
`

const animationID = 'some-hashed-text'

const AnimationComponent = props => (
  <Animation
    transitionName={animationID}
    transitionEnterTimeout={0.1}
    transitionLeaveTimeout={2000}
  >
    <div>some content</div>
  </Animation>
)

我不想按照另一个答案中的建议使用 injectGlobal,因为我需要对每个组件进行不同的转换。

事实证明这很简单 - 只需将过渡 类 嵌套在组件的样式中即可:

import React from "react";
import CSSTransitionGroup from 'react-transition-group/CSSTransitionGroup';
import styled from 'styled-components';

const appearDuration = 500;
const transitionName = `example`;

const Container = styled.section`
        font-size: 1.5em;
        padding: 0;
        margin: 0;

        &.${transitionName}-appear {
            opacity: 0.01;
        }

        &.${transitionName}-appear-active {
            opacity: 1;
            transition: opacity ${appearDuration}ms ease-out;
        }`;

export default () => {

    return (
        <CSSTransitionGroup
            transitionName={transitionName}
            transitionAppear={true}
            transitionAppearTimeout={appearDuration}>
            <Container>
                This will have the appear transition applied!
            </Container>
        </CSSTransitionGroup>
    );
};

请注意,我使用的是较新的 CSSTransitionGroup,而不是 ReactCSSTransitionGroup,但它也应该适用。

很棒,但我必须做一些小的改动才能让它发挥作用。我改变了 <CSSTransition> 的属性,并使用一个函数作为它的 child。

请参阅下面的组件示例,该组件会根据状态变化淡出 in/out:

import React, { Component } from "react";
import ReactDOM from "react-dom";
import { CSSTransition } from "react-transition-group";
import styled from "styled-components";

const Box = styled.div`
  width: 300px;
  height: 300px;
  background: red;
  transition: opacity 0.3s;

  // enter from
  &.fade-enter {
    opacity: 0;
  }

  // enter to
  &.fade-enter-active {
    opacity: 1;
  }

  // exit from
  &.fade-exit {
    opacity: 1;
  }

  // exit to 
  &.fade-exit-active {
    opacity: 0;
  }
}`;

export default class App extends Component {
  constructor() {
    super();
    this.state = {
      active: true
    };

    setInterval(() => this.setState({ active: !this.state.active }), 1000);
  }

  render() {
    return (
      <CSSTransition
        in={this.state.active}
        classNames="fade"
        timeout={300}
        unmountOnExit
      >
        {() => <Box />}
      </CSSTransition>
    );
  }
}
import React from "react";
import { CSSTransition } from 'react-transition-group';

const styles = theme => ({
    'fade-enter':{
        opacity: 0,
    },
    'fade-enter-active':{
        opacity: 1,
        transition: "opacity 300ms"
    },
    'fade-exit':{
        opacity: 1,
    },
    'fade-exit-active':{
        opacity: 0,
        transition: "opacity 300ms"
    },
})

class myAnimatedComponent extends React.Component {

  constructor(props){
    super(props);
  }

  render(){

    let {classes} = this.props;

    return (
        <CSSTransition
            in={this.props.conditionVariable}
            classNames={{
               enter: classes['fade-enter'],
               enterActive: classes['fade-enter-active'],
               exit: classes['fade-exit'],
               exitActive: classes['fade-exit-active'],
            }}
            timeout={300}
            unmountOnExit>
                <span>This will have the transition applied to it!</span>
        </CSSTransition>
    );
  }
};

export default (styles)(myAnimatedComponent);

我不得不使用 classes['fade-enter'] 等,因为 React 更改了这个组件中所有 类 的名称,因为我使用了 withStyles。也正因为如此,当我导出组件时,React 将我的 类 插入到该组件的道具中,这就是为什么我还必须创建一个名为 类 的变量来捕获那些 类。

有一个很棒的博客 post 解释了如何做到这一点: https://dev.to/terrierscript/styled-component--react-transition-group--very-simple-transition-jja

他们使用 react-transition-group 提供的低级别 Transiton 组件: http://reactcommunity.org/react-transition-group/transition

// This is overly simplified, but styles change depend on state from Transition
const MyStyledComponent = styled.div`
  transform: translateY(${({ state }) => (state === 'exited' ? "0" : "-100%")});
  transition: transform 2s;
`

const App = () =>
  <Transition in={animate} timeout={500}>
    {(state) => (
      // state change: exited -> entering -> entered -> exiting -> exited
      <MyStyledComponent state={state}>Hello</MyStyledComponent>
    )}
  </Transition>