MST
星途 面试题库

面试题:React 中如何通过条件渲染优化列表渲染性能

在 React 应用中,有一个包含大量数据项的列表需要根据某个条件进行渲染。例如,一个待办事项列表,当用户点击‘显示已完成’按钮时,显示所有已完成的事项;当点击‘显示未完成’按钮时,显示所有未完成的事项。请描述实现该功能并优化性能的思路,且说明在条件渲染过程中可能遇到的性能问题及解决方案。
49.8万 热度难度
前端开发React

知识考点

AI 面试

面试题答案

一键面试

实现功能思路

  1. 状态管理
    • 在 React 组件中,使用 useState 钩子来管理当前的显示状态(比如 showCompleted 布尔值),初始值可以设为 false 表示默认显示未完成事项。
    • 例如:
    import React, { useState } from'react';
    const TodoList = () => {
      const [showCompleted, setShowCompleted] = useState(false);
      // 待办事项数据
      const todos = [
        { id: 1, text: '事项1', completed: false },
        { id: 2, text: '事项2', completed: true }
      ];
      return (
        <div>
          <button onClick={() => setShowCompleted(!showCompleted)}>
            {showCompleted? '显示未完成' : '显示已完成'}
          </button>
          {/* 渲染列表 */}
        </div>
      );
    };
    export default TodoList;
    
  2. 列表渲染
    • 根据 showCompleted 的值过滤待办事项列表。
    • 使用 map 方法遍历过滤后的列表,并渲染每个事项。
    • 例如:
    const filteredTodos = showCompleted? todos.filter(todo => todo.completed) : todos.filter(todo =>!todo.completed);
    {filteredTodos.map(todo => (
      <div key={todo.id}>
        {todo.text} - {todo.completed? '已完成' : '未完成'}
      </div>
    ))}
    

性能优化思路

  1. 虚拟列表
    • 由于数据项较多,使用虚拟列表库(如 react - virtualizedreact - window)。这些库只会渲染可见区域的列表项,大大减少了 DOM 节点数量,提升性能。
    • 例如使用 react - virtualizedList 组件:
    import { List } from'react - virtualized';
    const rowRenderer = ({ index, key, style }) => {
      const todo = filteredTodos[index];
      return (
        <div key={key} style={style}>
          {todo.text} - {todo.completed? '已完成' : '未完成'}
        </div>
      );
    };
    <List
      height={400}
      rowCount={filteredTodos.length}
      rowHeight={50}
      rowRenderer={rowRenderer}
      width={300}
    />
    
  2. Memoization
    • 使用 React.memo 包裹列表项组件,避免不必要的重新渲染。如果列表项组件的 props 没有变化,它不会重新渲染。
    • 例如:
    const TodoItem = React.memo(({ todo }) => (
      <div>
        {todo.text} - {todo.completed? '已完成' : '未完成'}
      </div>
    ));
    
    • 对于过滤后的列表数据,可以使用 useMemo 来缓存计算结果,避免每次状态变化都重新计算。
    • 例如:
    const filteredTodos = useMemo(() => {
      return showCompleted? todos.filter(todo => todo.completed) : todos.filter(todo =>!todo.completed);
    }, [showCompleted, todos]);
    

可能遇到的性能问题及解决方案

  1. 大量 DOM 渲染
    • 问题:当列表数据量很大时,渲染所有列表项会导致 DOM 操作性能下降,页面卡顿。
    • 解决方案:采用虚拟列表技术,只渲染可见区域的列表项。
  2. 不必要的重新渲染
    • 问题:父组件状态变化可能导致子组件不必要的重新渲染,浪费性能。
    • 解决方案:使用 React.memo 包裹子组件,或者使用 shouldComponentUpdate(类组件中)来控制组件的重新渲染。同时,对于复杂计算,使用 useMemouseCallback 来缓存计算结果和回调函数,避免不必要的重复计算。