面试题答案
一键面试实现功能思路
- 状态管理:
- 在 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;
- 在 React 组件中,使用
- 列表渲染:
- 根据
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> ))}
- 根据
性能优化思路
- 虚拟列表:
- 由于数据项较多,使用虚拟列表库(如
react - virtualized
或react - window
)。这些库只会渲染可见区域的列表项,大大减少了 DOM 节点数量,提升性能。 - 例如使用
react - virtualized
的List
组件:
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} />
- 由于数据项较多,使用虚拟列表库(如
- 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]);
- 使用
可能遇到的性能问题及解决方案
- 大量 DOM 渲染:
- 问题:当列表数据量很大时,渲染所有列表项会导致 DOM 操作性能下降,页面卡顿。
- 解决方案:采用虚拟列表技术,只渲染可见区域的列表项。
- 不必要的重新渲染:
- 问题:父组件状态变化可能导致子组件不必要的重新渲染,浪费性能。
- 解决方案:使用
React.memo
包裹子组件,或者使用shouldComponentUpdate
(类组件中)来控制组件的重新渲染。同时,对于复杂计算,使用useMemo
或useCallback
来缓存计算结果和回调函数,避免不必要的重复计算。