MST
星途 面试题库

面试题:React无限滚动列表中如何优雅地处理动态数据更新

假设在一个React无限滚动列表场景中,列表数据可能会随时新增、删除或修改,不仅是在用户滚动加载新数据时,还可能在其他业务操作触发时。请描述你会如何设计架构和编写代码,使得列表在面对这些动态数据更新时,能够保持高效且正确的展示,同时确保滚动位置、加载状态等不受影响,并解释关键代码的实现思路。
10.5万 热度难度
前端开发React

知识考点

AI 面试

面试题答案

一键面试

架构设计

  1. 状态管理:使用 React 的 useState 或状态管理库(如 Redux、MobX)来管理列表数据。例如,使用 useState 定义一个数组来存储列表项数据,同时定义一个状态来表示加载状态(loading)。
import React, { useState, useEffect } from 'react';

const InfiniteScrollList = () => {
    const [listData, setListData] = useState([]);
    const [loading, setLoading] = useState(false);
    // 其他逻辑...
};
  1. 滚动监听:使用 useEffect 结合 window.addEventListener('scroll', callback) 来监听滚动事件。当滚动到页面底部一定距离时,触发加载新数据的操作。
useEffect(() => {
    const handleScroll = () => {
        const scrollTop = document.documentElement.scrollTop || document.body.scrollTop;
        const clientHeight = document.documentElement.clientHeight;
        const scrollHeight = document.documentElement.scrollHeight;
        if (scrollTop + clientHeight >= scrollHeight - 100 &&!loading) {
            setLoading(true);
            // 加载新数据的逻辑
        }
    };
    window.addEventListener('scroll', handleScroll);
    return () => {
        window.removeEventListener('scroll', handleScroll);
    };
}, [loading]);
  1. 数据更新处理:当数据新增、删除或修改时,通过更新 listData 状态来触发 React 的重新渲染。为了确保滚动位置不受影响,可以记录当前滚动位置,在数据更新后恢复滚动位置。
// 新增数据
const addData = newData => {
    const currentScrollTop = document.documentElement.scrollTop || document.body.scrollTop;
    setListData([...listData, newData]);
    setTimeout(() => {
        document.documentElement.scrollTop = currentScrollTop;
    }, 0);
};

// 删除数据
const deleteData = index => {
    const currentScrollTop = document.documentElement.scrollTop || document.body.scrollTop;
    const newListData = listData.filter((_, i) => i!== index);
    setListData(newListData);
    setTimeout(() => {
        document.documentElement.scrollTop = currentScrollTop;
    }, 0);
};

// 修改数据
const updateData = (index, updatedData) => {
    const currentScrollTop = document.documentElement.scrollTop || document.body.scrollTop;
    const newListData = [...listData];
    newListData[index] = updatedData;
    setListData(newListData);
    setTimeout(() => {
        document.documentElement.scrollTop = currentScrollTop;
    }, 0);
};

关键代码实现思路

  1. 滚动监听:在 useEffect 中添加和移除滚动事件监听器,通过计算滚动高度、可视区域高度和文档总高度来判断是否接近页面底部,从而触发加载新数据。
  2. 数据更新:无论是新增、删除还是修改数据,都先记录当前滚动位置,更新状态后使用 setTimeout 在微任务队列中恢复滚动位置。这是因为 React 的状态更新是异步的,直接在更新状态后设置滚动位置可能会导致无效操作,setTimeout 确保在 DOM 更新完成后再恢复滚动位置。
  3. 加载状态管理:通过 loading 状态来避免重复触发加载新数据的操作,确保每次滚动加载时只有在当前没有处于加载状态下才会执行加载逻辑。