MST

星途 面试题库

面试题:React中如何基于requestAnimationFrame实现高性能动画且处理好性能优化与交互同步问题

在React应用中,使用`requestAnimationFrame`实现一个高性能的组件动画,组件需要根据用户的滚动操作实时改变动画状态(比如滚动速度影响动画播放速度)。同时,要考虑到动画在不同帧率设备上的性能优化,避免内存泄漏和卡顿。请阐述整体实现方案并给出核心代码逻辑。
48.3万 热度难度
前端开发React

知识考点

AI 面试

面试题答案

一键面试

整体实现方案

  1. 获取滚动事件:使用window.addEventListener('scroll', callback)监听滚动事件,在回调函数中获取当前滚动位置。
  2. 计算滚动速度:记录上一次滚动位置,通过与当前滚动位置的差值和时间间隔来计算滚动速度。
  3. 使用requestAnimationFrame:利用requestAnimationFrame来实现动画,该方法会在浏览器下一次重绘之前调用传入的回调函数,确保动画流畅。
  4. 性能优化
    • 节流:为了避免滚动事件过于频繁触发,导致性能问题,可以使用节流函数,限制回调函数在一定时间内只执行一次。
    • 取消监听:在组件卸载时,取消滚动事件的监听,防止内存泄漏。
    • 帧率自适应:根据设备的刷新率动态调整动画速度,确保在不同帧率设备上都能流畅运行。

核心代码逻辑

import React, { useEffect, useRef } from 'react';

const AnimatedComponent = () => {
    const animationFrameRef = useRef(null);
    const previousScrollTopRef = useRef(0);
    const previousTimeRef = useRef(null);

    const handleScroll = () => {
        const currentScrollTop = window.pageYOffset;
        const currentTime = performance.now();
        if (previousTimeRef.current) {
            const scrollSpeed = (currentScrollTop - previousScrollTopRef.current) / (currentTime - previousTimeRef.current);
            // 根据滚动速度调整动画状态,这里简单以log形式展示
            console.log(`Scroll speed: ${scrollSpeed}`);
        }
        previousScrollTopRef.current = currentScrollTop;
        previousTimeRef.current = currentTime;
    };

    const animate = () => {
        // 这里进行具体的动画操作,例如改变组件的样式
        // 这里简单以log形式展示
        console.log('Animation frame');
        animationFrameRef.current = requestAnimationFrame(animate);
    };

    useEffect(() => {
        window.addEventListener('scroll', handleScroll);
        animationFrameRef.current = requestAnimationFrame(animate);
        return () => {
            window.removeEventListener('scroll', handleScroll);
            cancelAnimationFrame(animationFrameRef.current);
        };
    }, []);

    return (
        <div>
            {/* 组件内容 */}
        </div>
    );
};

export default AnimatedComponent;

以上代码展示了如何在React组件中监听滚动事件并结合requestAnimationFrame实现动画。handleScroll函数负责计算滚动速度,animate函数负责执行动画帧,useEffect钩子用于添加和移除滚动事件监听以及启动和取消动画。