React 项目集成——hooks 封装与组件化
方式一:自行封装(最轻量)
直接用 useRef + useEffect 封装:
import { useEffect, useRef } from 'react';
import lottie from 'lottie-web';
function LottieAnimation({ src, loop = true, autoplay = true, className }) {
const containerRef = useRef(null);
const animationRef = useRef(null);
useEffect(() => {
if (!containerRef.current) return;
animationRef.current = lottie.loadAnimation({
container: containerRef.current,
renderer: 'svg',
loop,
autoplay,
path: src,
});
return () => {
animationRef.current?.destroy();
};
}, [src, loop, autoplay]);
return <div ref={containerRef} className={className} />;
}
// 使用
export default function App() {
return (
<LottieAnimation
src="/loading.json"
className="w-64 h-64"
/>
);
}
关键点:
- 用
useRef持有 DOM 容器和 player 对象。 useEffect负责创建动画,返回的清理函数负责destroy()——组件卸载时必须销毁动画,否则内存泄漏。src变化时 effect 重跑,自动销毁旧动画并创建新的。
方式二:用现成组件库
lottie-react
最流行的 React 封装:
npm install lottie-react
import Lottie from 'lottie-react';
import loadingData from './loading.json';
<Lottie animationData={loadingData} loop autoplay />
优点是简单、声明式、自动处理销毁和生命周期。
@lottiefiles/lottie-player
见 lottie-player 组件。React 里直接把 Web Component 当 JSX 用:
import '@lottiefiles/lottie-player';
<lottie-player
src="/loading.json"
autoplay
loop
style={{ width: 256, height: 256 }}
/>
性能注意事项
JSON 文件打包 vs CDN
// 方式一:import JSON(打包进 bundle,增加体积但首屏快)
import loadingData from './loading.json';
<Lottie animationData={loadingData} />
// 方式二:远程加载 URL(不增 bundle,异步加载有延迟)
<Lottie lottieFile="你的 CDN 托管地址" />
组件频繁重渲染
如果 Lottie 组件在一个频繁重渲染的父组件里,player 对象会被反复销毁重建。用 React.memo 包裹:
const MemoizedLottie = React.memo(function LottieAnimation({ src }) {
// ...
});
动画数量多的场景
如果一个页面有大量 Lottie 动画(比如列表里每行一个小图标动画),考虑:
- 用
canvas渲染器代替svg(减少 DOM 节点)。 - 只在动画进入视口时创建(IntersectionObserver)。
- 或者只用静态版本展示,hover 时才启动动画。