react 路由切换过渡效果

发布于2024-04-18 17:58:28字数7

版本

  1. React 18.2.0
  2. React router 6.22.3
  3. react-transition-group 4.4.5

React Transition group

一个React库,这个库提供了一组用于定义进入和退出转换的简单组件。React Transition Group不是一个像React- motion那样的动画库,它自己做不动画样式而是通过管理class和元素由开发者自定义过渡效果。

Transition、CSSTransition、SwitchTransition、TransitionGroup

Transition是一个与平台无关的基础组件,允许你使用简单的声明性API描述从一个组件状态到另一个状态的转换。最常见的是,它用于动画组件的安装和卸载,但也可以用来描述就地过渡状态。
CSSTransition建立在Transition组件之上,所以它继承了Transition组件的所有道具,从名称上看,我们也能看出CSSTransition是需要结合css完成样式定义的;这两者的区别就是Transition更关注状态的转换和跟踪,而CSSTransition则是更具体、方便的组件(已经实现了添加、移除类名)。
SwitchTransition用过vue的transition都会感到熟悉,受vue转换模式启发的转换组件(官网文档说的);不同于vue的transition的是SwitchTransition是基于子组件的key(Transition或cstransition组件)进行转换的。
TransitionGroup用于管理一组转换组件(< transition >和< cstransition >),这个组件主要用于处理列表中元素的过渡动画。它可以将多个动画组件包裹在其中,通过管理一组组件的进入和退出状态,实现列表或其他集合中元素的动画效果。

结合react路由于antd layout的例子

import { Layout } from "antd";
import { useRef } from "react";
import { useOutlet } from "react-router-dom";
import { SwitchTransition, CSSTransition } from "react-transition-group";
import { useLocation } from "react-router-dom";

function Transition() {
	const location = useLocation();
	const nodeRef = useRef(null);
	const currentOutlet = useOutlet();
	return (
		<SwitchTransition mode="out-in">
			<CSSTransition key={location.key} timeout={300} classNames="page" nodeRef={nodeRef}>
				<Layout.Content
					ref={nodeRef}
					style={{
						transition: "all 0.5s",
					}}>
					{currentOutlet}
				</Layout.Content>
			</CSSTransition>
		</SwitchTransition>
	);
}
.page-enter {
	opacity: 0;
	transform: translateX(-30px);
}
.page-exit {
	opacity: 0;
	transform: translateX(30px);
}

需要注意⚠️的点

  1. 在网上搜到的很多例子中都会出现CSSTransition内的元素没有给ref赋值,而CSSTransition是通过ref来正确地识别并处理DOM节点的挂载和卸载(虽然不加也能识别到);如果你的react项目开启了StrictMode在开发阶段还会出现错误信息,所以为了更准确识别而且为了不显示那该死的报错信息还是加上吧🤷
  2. SwitchTransitionTransitionGroup的区别:网上很多例子(没办法🤷,学一个东西前先看看别人怎么用的)会用到TransitionGroup组件进行页面过渡,我这边是不建议页面过渡用该组件的,TransitionGroup组件管理的是一组组件的动画状态,这通常涉及到列表项的增加、减少或重新排序,所以我们从页面节点从可以看到当切换页面时会短暂的(可以给CSSTransition加大timeout的值看得更清楚)出现两个页面同时存在在界面中,而SwitchTransition则是关注两个组件之间的状态切换,确保在切换过程中动画的流畅性和连贯性,在我的例子中也能看出main元素(Layout.Content)在过渡过程中只改变了class,明显SwitchTransition组件更符合我们页面过渡效果的预期。
  3. 使用useOutlet而不是<Outlet />;先说一下这两个的区别,<Outlet />是一个受控组件,它将要渲染的组件是由路由组件控制的,当路由发生变化时,它会自动更新渲染;useOutlet则是一个hook,它是一个非受控组件,用于在组件中获取当前嵌套路由的信息,如果嵌套路由没有挂载,则返回null;如果挂载了则返回嵌套的路由对象。而在我们这个例子中如果使用了<Outlet />,你会发现在路由跳转时页面会先出现然后在进行过渡动画(闪了一下),这是由于它是受控组件,在路由变化时就提前渲染了,导致过渡组件反应稍慢了一些;使用useOutlet则不会有这种情况。

评论

back top