react-router.4-实现路由跳转动画

使用插件

react-router-dom 4.2.2 用于路由
react-transition-group 2.2.1 用于react动画实现,这里需要注意下,使用的不是版本1,而是只包含{Transition, TransitionGroup, CSSTransition}的版本2
animate.css 用于动画效果

react-router.4.0

此段大部分来自 :简书 作者:大神来搬砖
使用 Route组件时有三个引用组件的属性
1.component
2.render
3.children

文档对componet属性的描述

When you use component (instead of render or children, below) the router uses React.createElement to create a new 
React element from the given component. That means if you provide an inline function to the component prop, you 
would create a new component every render. This results in the existing component unmounting and the new 
component mounting instead of just updating the existing component. When using an inline function for inline 
rendering, use the render or the children prop (below).
----------------------------------------
使用组件(而不是下面的render或children)时,路由器使用React.createElement从给定组件创建新的React元素。这意
味着,如果为组件属性提供内联函数,则每次渲染都将创建一个新组件。这导致现有组件卸载和新组件安装而不仅仅是
更新现有组件。使用内联函数进行内联渲染时,请使用渲染或子属性(如下所示)。

举例

import React from 'react';
import ReactDOM from 'react-dom';
import {BrowserRouter, Route} from "react-router-dom";

class Bar extends React.Component {

    componentDidMount() {
        console.log("componentDidMount")
    }

    render() {
        return (
            <div>Bar</div>
        )
    }
}

class App extends React.Component {

    constructor(prop) {
        super(prop);
        this.state = {idx: 1}
    }

    handleClick = () => {
        this.setState(state => ({idx: state.idx + 1}))
    };

    render() {
        return (
            <div>
                <div>
                    {this.state.idx}
                    <button onClick={this.handleClick}>add</button>
                </div>
                <div>
                    <BrowserRouter>
                        <Route component={Bar}/>
                    </BrowserRouter>
                </div>
            </div>
        );
    }
}


ReactDOM.render(<App/>, document.getElementById('root'));

上面的代码中,App组件内有一个简单的Bar组件,通过component属性被Route引用。

<Route component={Bar}/>

此时在页面中点击按钮,Bar组件的componentDidMount并不会被触发。
假设现在需要在Bar组件中接受App中的idx,需要将idx作为props传递给Bar,此时可以写成如下代码

import React from 'react';
import ReactDOM from 'react-dom';
import {BrowserRouter, Route} from "react-router-dom";

class Bar extends React.Component {

    componentDidMount() {
        console.log("componentDidMount")
    }

    render() {
        const {idx} = this.props;
        return (
            <div>in Bar : {idx}</div>
        )
    }
}

class App extends React.Component {

    constructor(prop) {
        super(prop);
        this.state = {idx: 1}
    }

    handleClick = () => {
        this.setState(state => ({idx: state.idx + 1}))
    };

    render() {
        return (
            <div>
                <div>
                    {this.state.idx}
                    <button onClick={this.handleClick}>add</button>
                </div>
                <div>
                    <BrowserRouter>
                        <Route component={() => (<Bar idx={this.state.idx}/>)}/>
                    </BrowserRouter>
                </div>
            </div>
        );
    }
}


ReactDOM.render(<App/>, document.getElementById('root'));

然而此时点击按钮,发现Bar的componentDidMount一直被调用,就像上面文档中说的一样

所以正确的写法应该是

<Route render={() => (<Bar idx={this.state.idx}/>)}/>
render是一个函数,语法:render={()=>{return <div></div>}},只要你的路由匹配了,这个函数才会执行
children也是一个函数,不管匹配不匹配,这个函数都会执行

动画思路

!!! 函数式组件和类组件要合理使用 建议先使用类组件 !!!
动画主要是通过 react-transition-group来实现的
引出里面的CSSTransition组件 包裹组件
动画效果使用 animate.css来实现里面的动画都是写好的
动画的关键是 下面className里面的  in intrue为动画进场false为动画出场
以下控制in的方案有两个
	1.通过在LayOut组件(外部包裹组件)做路由监听,设置一个flag初始值为false,但路由路径变为相应组
	的路径时设置flag为ture,否则为false
	2.通过mtach来判断  使用<Route/>组件里属性使用children,但路由路径匹配时match!==null否则就是
	null 
最后可以封装成高阶组件做代码优化
 
 //路由组件中
 <Route path='/home/details' children={(props) => <Details {...props}></Details>} />

//被路由组件使用的组件中
 <CSSTransition
            // in={props.match !== null}
            in={DtFlag}
            timeout={2000}		//动画时间
            mountOnEnter
            unmountOnExit
            classNames={{
                enter: 'animated',
                enterActive: 'slideInLeft',//入场动画
                exit: 'animated',
                exitActive: 'bounceOut',  //出场动画
            }}
        >
            <div className='details-box'>//展示的内容
                <Head {...props} />
                <Cont {...props} />
                <Footer {...props} />
            </div>
        </CSSTransition>

动画思路来自 :简书 作者:我只是个NPC

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值