MST

星途 面试题库

面试题:React 列表中事件处理的性能优化

在一个 React 应用中,有一个大数据量的列表,每个列表项都绑定了一个复杂的事件处理函数(例如,该函数需要进行大量的计算和 API 调用)。请分析这种情况下可能出现的性能问题,并阐述至少两种优化方案,同时给出相关代码示例。
47.4万 热度难度
前端开发React

知识考点

AI 面试

面试题答案

一键面试

可能出现的性能问题

  1. 初始渲染性能问题:大数据量列表渲染时,每个列表项都绑定复杂事件处理函数,会导致 React 初始渲染时创建大量的函数实例,增加内存开销,使得渲染时间变长,页面卡顿。
  2. 交互性能问题:当用户与列表项交互触发事件时,复杂的事件处理函数需要进行大量计算和 API 调用,这会阻塞主线程,导致页面失去响应,影响用户体验。

优化方案

  1. 使用 useCallback 缓存事件处理函数
    • 原理useCallback 会返回一个 memoized 回调函数,只有当依赖项发生变化时,才会返回新的函数。这样可以避免在每次渲染时都创建新的事件处理函数实例。
    • 代码示例
import React, { useState, useCallback } from'react';

const BigDataList = () => {
    const [data, setData] = useState(Array.from({ length: 1000 }, (_, i) => i + 1));

    const handleComplexEvent = useCallback((item) => {
        // 模拟大量计算和 API 调用
        console.log(`处理列表项 ${item} 的复杂事件`);
        // 实际中这里可以是 API 调用等复杂操作
    }, []);

    return (
        <ul>
            {data.map(item => (
                <li key={item} onClick={() => handleComplexEvent(item)}>{item}</li>
            ))}
        </ul>
    );
};

export default BigDataList;
  1. 虚拟列表
    • 原理:只渲染当前视口内可见的列表项,当用户滚动时,动态加载新的可见项,从而大大减少同时渲染的列表项数量,提高性能。
    • 代码示例
import React, { useState, useRef, useEffect } from'react';

const VirtualList = () => {
    const totalItems = 1000;
    const itemHeight = 30;
    const viewportHeight = window.innerHeight;
    const visibleItemCount = Math.floor(viewportHeight / itemHeight);
    const [startIndex, setStartIndex] = useState(0);
    const listRef = useRef(null);

    const handleScroll = () => {
        const scrollTop = listRef.current.scrollTop;
        const newStartIndex = Math.floor(scrollTop / itemHeight);
        setStartIndex(newStartIndex);
    };

    useEffect(() => {
        const list = listRef.current;
        list.addEventListener('scroll', handleScroll);
        return () => {
            list.removeEventListener('scroll', handleScroll);
        };
    }, []);

    const data = Array.from({ length: totalItems }, (_, i) => i + 1);
    const visibleData = data.slice(startIndex, startIndex + visibleItemCount);

    const handleComplexEvent = (item) => {
        // 模拟大量计算和 API 调用
        console.log(`处理列表项 ${item} 的复杂事件`);
        // 实际中这里可以是 API 调用等复杂操作
    };

    return (
        <div
            ref={listRef}
            style={{ height: viewportHeight, overflowY: 'auto' }}
        >
            <div style={{ height: totalItems * itemHeight }}>
                {visibleData.map(item => (
                    <div
                        key={item}
                        style={{ height: itemHeight, borderBottom: '1px solid #ccc', padding: '5px' }}
                        onClick={() => handleComplexEvent(item)}
                    >
                        {item}
                    </div>
                ))}
            </div>
        </div>
    );
};

export default VirtualList;
  1. 节流或防抖处理事件
    • 原理:节流(Throttle)是指在一定时间内,只允许事件处理函数执行一次,无论触发频率多高。防抖(Debounce)是指当事件触发后,等待一定时间,如果在这段时间内事件再次触发,则重新计时,直到计时结束才执行事件处理函数。这样可以减少频繁触发事件导致的大量计算和 API 调用。
    • 代码示例(节流)
import React, { useState } from'react';

const throttle = (func, delay) => {
    let timer = null;
    return function() {
        if (!timer) {
            func.apply(this, arguments);
            timer = setTimeout(() => {
                timer = null;
            }, delay);
        }
    };
};

const BigDataListThrottle = () => {
    const [data, setData] = useState(Array.from({ length: 1000 }, (_, i) => i + 1));

    const handleComplexEvent = throttle((item) => {
        // 模拟大量计算和 API 调用
        console.log(`处理列表项 ${item} 的复杂事件`);
        // 实际中这里可以是 API 调用等复杂操作
    }, 300);

    return (
        <ul>
            {data.map(item => (
                <li key={item} onClick={() => handleComplexEvent(item)}>{item}</li>
            ))}
        </ul>
    );
};

export default BigDataListThrottle;
  • 代码示例(防抖)
import React, { useState } from'react';

const debounce = (func, delay) => {
    let timer = null;
    return function() {
        if (timer) {
            clearTimeout(timer);
        }
        timer = setTimeout(() => {
            func.apply(this, arguments);
            timer = null;
        }, delay);
    };
};

const BigDataListDebounce = () => {
    const [data, setData] = useState(Array.from({ length: 1000 }, (_, i) => i + 1));

    const handleComplexEvent = debounce((item) => {
        // 模拟大量计算和 API 调用
        console.log(`处理列表项 ${item} 的复杂事件`);
        // 实际中这里可以是 API 调用等复杂操作
    }, 300);

    return (
        <ul>
            {data.map(item => (
                <li key={item} onClick={() => handleComplexEvent(item)}>{item}</li>
            ))}
        </ul>
    );
};

export default BigDataListDebounce;