react-transition-group 探究(一)

565 阅读3分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第21天,点击查看活动详情

Exposes simple components useful for defining entering and exiting transitions. React Transition Group is not an animation library like React-Motion, it does not animate styles by itself. Instead it exposes transition stages, manages classes and group elements and manipulates the DOM in useful ways, making the implementation of actual visual transitions much easier.

公开用于定义进入和退出转换的简单组件。 React Transition Group 不是像 React-Motion 那样的动画库,它本身不会为样式设置动画。相反,它公开了过渡阶段,管理类和组元素,并以有用的方式操作 DOM,使实际视觉过渡的实现更加容易。

文档:reactcommunity.org/react-trans…

网上的博客用法:www.jianshu.com/p/49fa164b9…

blog.csdn.net/qq_37279880…

源码:github.com/reactjs/rea…

组件说明
Transition过渡组件
CSSTransition动画进入出入组件
SwitchTransition动画却换组件
TransitionGroup列表动画组件

Transition

The Transition component lets you describe a transition from one component state to another over time with a simple declarative API. Most commonly it's used to animate the mounting and unmounting of a component, but can also be used to describe in-place transition states as well.

Transition 组件允许您使用简单的声明式 API 描述随时间从一个组件状态到另一个组件状态的转换。最常见的是它用于动画组件的安装和卸载,但也可用于描述就地过渡状态

默认情况下,只跟踪组件的进入和退出状态。效果还要靠自己

There are 4 main states a Transition can be in:

  • 'entering' 进入中
  • 'entered' 进入后
  • 'exiting' 离开中
  • 'exited' 离开后

属性

in 显示组件;触发进入或退出状态,默认false

timeout 动画时间

children 接收state状态的函数组件或者元素

例子

import { useState } from "react";
import "./App.css";
import { Transition } from "react-transition-group";

const duration = 300;
// 动画 样式 
const defaultStyle = {
  transition: `opacity ${duration}ms ease-in-out`,
  opacity: 0,
};

const transitionStyles = {
  entering: { opacity: 1 },
  entered: { opacity: 1 },
  exiting: { opacity: 0 },
  exited: { opacity: 0 },
};
function App() {
  const [inProp, setInProp] = useState(false);
  return (
    <div className="App">
      <header className="App-header">
      {/* in 显示组件;触发进入或退出状态,默认false。 timeout 动画时间 */}
        <Transition in={inProp} timeout={duration}>
          {(state) => (
            <div
              style={{
                ...defaultStyle,
                ...transitionStyles[state],
              }}
            >
              I'm a fade Transition!
            </div>
          )}
        </Transition>
        <button onClick={() => setInProp(!inProp)}>Click to Enter</button>
      </header>
    </div>
  );
}

export default App;

默认是exited,当inture时,进入 进入中 的状态,timeout时间后变成 进入后 的状态

intruefalse,则进入 离开中 状态,timeout时间后变成 离开后 的状态

实现过程

  • 先完成架构, 注入子组件传递动画状态。初始状态通过判断in得出是进入后或者离开后。
import React from 'react';
const ENTERING = 'entering'
const ENTERED = 'entered'
const EXITING = 'exiting'
const EXITED = 'exited'
class Transition extends React.Component {
    constructor(props) {
        super(props);
        this.state = {
            status: props.in ? ENTERED : EXITED
        };
    }
    render() {
        const { children } = this.props
        const { status } = this.state
        return (
            children(status)
        )
    }
}
export default Transition

  • 组件状态的变化是通过 in来更改的,所以通过 componentDidUpdate 去 监听,当intrue,状态要改为进入中,且 在 过渡时间后改成 进入后,反之。。。
   componentDidUpdate() {
        const { status } = this.state
        const { in: nextIn } = this.props
        console.log(this.props)
    
            // 如果 in 为true,且 状态是离开后,那状态要改成进入中
            if (nextIn) {
                this.setState({
                    status: ENTERING
                })
                // 并且 要在 动画时间后改变状态
                setTimeout(() => {
                    this.setState({
                        status: ENTERED
                    })
                }, this.props.timeout)

                // in 为 false 状态是进入后,则要改成离开中
            } else{
                this.setState({
                    status: EXITING
                })
                setTimeout(() => {
                    this.setState({
                        status: EXITED
                    })
                }, this.props.timeout)
            }
        
    }

优化的完整源码

import React from 'react';
const ENTERING = 'entering'
const ENTERED = 'entered'
const EXITING = 'exiting'
const EXITED = 'exited'
class Transition extends React.Component {
    constructor(props) {
        super(props);
        this.state = {
            status: props.in ? ENTERED : EXITED
        };
    }
    componentDidUpdate() {
        const { status } = this.state
        const { in: nextIn } = this.props
        console.log(this.props)
        if (nextIn) {
            // 优化,进入后和进入中就没必要改状态了
            if (status !== ENTERED && status !== ENTERING) {
                this.updateStatus(ENTERING)
            }
        } else {
            if (status !== EXITED && status !== EXITING) {
                this.updateStatus(EXITING)
            }
        }
    }
    updateStatus(status) {
        if (status == ENTERING) {
            this.performEnter()
        } else if (status == EXITING) {
            this.performExit()
        }
    }
    performEnter = () => {
        const { timeout } = this.props
        this.setState({
            status: ENTERING
        }, () => {
            this.onTransitionEnd(timeout, () => this.setState({ status: ENTERED }))
        })
    }
    performExit = () => {
        const { timeout } = this.props
        this.setState({
            status: EXITING
        }, () => {
            this.onTransitionEnd(timeout, () => this.setState({ status: EXITED }))
        })
    }
    onTransitionEnd = (timeout, callback) => {
        setTimeout(callback, timeout)
    }
    render() {
        const { children } = this.props
        const { status } = this.state
        return (
            children(status)
        )
    }
}
export { Transition }

还有三种组件,下期说