面试题答案
一键面试优化思路
- 事件委托:利用事件冒泡机制,将事件监听器绑定在父元素上,而不是每个动态生成的子元素。这样,无论添加或移除多少子元素,都只需维护一个父元素上的监听器,减少内存开销。
- 虚拟DOM复用:React通过虚拟DOM来高效更新实际DOM。确保在组件更新时,尽量复用已有的虚拟DOM节点,减少不必要的重新渲染。
- 合理使用生命周期钩子:在组件卸载时,及时清理事件监听器,避免内存泄漏。
- 节流与防抖:对于频繁触发的事件(如聊天窗口的滚动事件),使用节流或防抖技术,限制事件触发频率,提高性能。
实现方案
- 事件委托实现:
import React, { useEffect } from 'react'; const ChatWindowList = () => { const handleClick = (event) => { // 判断点击的是否是聊天窗口元素 if (event.target.classList.contains('chat-window')) { // 处理聊天窗口点击逻辑 } }; useEffect(() => { document.addEventListener('click', handleClick); return () => { document.removeEventListener('click', handleClick); }; }, []); return ( <div className="chat-window-list"> {/* 动态生成的聊天窗口 */} </div> ); }; export default ChatWindowList;
- 优化组件渲染:
- 使用
React.memo
包裹无状态组件,避免不必要的重新渲染。 - 对于有状态组件,使用
shouldComponentUpdate
或useMemo
、useCallback
来控制渲染。
const ChatWindow = React.memo(({ windowId, message }) => { return ( <div className="chat-window" data-id={windowId}> {message} </div> ); });
- 使用
- 清理事件监听器:
- 在类组件中,使用
componentWillUnmount
生命周期钩子清理事件监听器。 - 在函数组件中,使用
useEffect
的返回函数清理。
import React, { useEffect } from'react'; const ChatWindow = ({ windowId }) => { useEffect(() => { const handleScroll = () => { // 处理聊天窗口滚动逻辑 }; const chatWindow = document.querySelector(`[data-id="${windowId}"]`); chatWindow.addEventListener('scroll', handleScroll); return () => { chatWindow.removeEventListener('scroll', handleScroll); }; }, [windowId]); return ( <div className="chat-window" data-id={windowId}> {/* 聊天窗口内容 */} </div> ); }; export default ChatWindow;
- 在类组件中,使用
- 节流与防抖实现:
- 使用
lodash
库中的debounce
和throttle
函数。
import React, { useEffect } from'react'; import { throttle } from 'lodash'; const ChatWindow = ({ windowId }) => { const handleScroll = () => { // 处理聊天窗口滚动逻辑 }; const throttledScroll = throttle(handleScroll, 200); useEffect(() => { const chatWindow = document.querySelector(`[data-id="${windowId}"]`); chatWindow.addEventListener('scroll', throttledScroll); return () => { chatWindow.removeEventListener('scroll', throttledScroll); throttledScroll.cancel(); }; }, [windowId]); return ( <div className="chat-window" data-id={windowId}> {/* 聊天窗口内容 */} </div> ); }; export default ChatWindow;
- 使用