面试题答案
一键面试更新Props和State避免不必要重渲染
- 使用React.memo:
- 对于展示商品的子组件,用
React.memo
包裹。React.memo
是一个高阶组件,它会对组件的Props进行浅比较。如果Props没有变化,组件就不会重新渲染。例如:
const ProductItem = React.memo(({ product }) => { return ( <div> <p>{product.name}</p> <p>{product.price}</p> </div> ); });
- 对于展示商品的子组件,用
- 浅比较Props和State:
- 在
shouldComponentUpdate
生命周期方法(在类组件中)或使用自定义Hook来实现类似功能(在函数组件中)。对于商品是否被选中、购物车数量等State,在更新前进行浅比较。例如,在类组件中:
class ProductList extends React.Component { shouldComponentUpdate(nextProps, nextState) { // 浅比较商品列表Props if (!shallowEqual(this.props.products, nextProps.products)) { return true; } // 浅比较购物车数量State if (this.state.cartCount!== nextState.cartCount) { return true; } return false; } //...其他组件逻辑 }
- 在函数组件中可以使用
useCallback
和useMemo
。例如,当有一个函数依赖于State或Props时:
const ProductList = ({ products }) => { const [cartCount, setCartCount] = useState(0); const handleAddToCart = useCallback(() => { setCartCount(cartCount + 1); }, [cartCount]); // 这里products依赖数组可以省略,因为如果products变化,组件会重新渲染,handleAddToCart会重新生成 const memoizedProducts = useMemo(() => products, [products]); //...渲染逻辑 };
- 在
- 批量更新:
- 在React中,当多个State更新在同一事件循环内发生时,React会批量更新。但在某些情况下(如原生DOM事件处理函数内),React不会自动批量更新。这时可以使用
unstable_batchedUpdates
(在React 18之前)或flushSync
(React 18及之后)。例如:
import React, { useState, useEffect } from'react'; import { flushSync } from'react-dom'; const ProductList = () => { const [cartCount, setCartCount] = useState(0); const [selectedProduct, setSelectedProduct] = useState(null); const handleClick = () => { flushSync(() => { setCartCount(cartCount + 1); setSelectedProduct({ id: 1, name: 'Sample Product' }); }); }; return ( <div> <button onClick={handleClick}>Add to Cart</button> <p>Cart Count: {cartCount}</p> {selectedProduct && <p>Selected Product: {selectedProduct.name}</p>} </div> ); };
- 在React中,当多个State更新在同一事件循环内发生时,React会批量更新。但在某些情况下(如原生DOM事件处理函数内),React不会自动批量更新。这时可以使用
处理大量商品数据时的策略
- 虚拟化列表:
- 使用像
react - virtualized
或react - window
这样的库。这些库只渲染当前可见的商品项,而不是渲染所有商品。例如,使用react - virtualized
的List
组件:
import React from'react'; import { List } from'react - virtualized'; const products = Array.from({ length: 1000 }, (_, i) => ({ id: i, name: `Product ${i}`, price: i * 10 })); const rowRenderer = ({ index, key, style }) => { const product = products[index]; return ( <div key={key} style={style}> <p>{product.name}</p> <p>{product.price}</p> </div> ); }; const ProductList = () => { return ( <List height={400} rowCount={products.length} rowHeight={50} rowRenderer={rowRenderer} width={300} /> ); };
- 使用像
- 分页:
- 将商品数据分成多个页面,每次只请求和渲染当前页面的数据。例如,在后端接口中添加分页参数:
const pageSize = 10; const [currentPage, setCurrentPage] = useState(1); const startIndex = (currentPage - 1) * pageSize; const endIndex = startIndex + pageSize; const currentProducts = products.slice(startIndex, endIndex); return ( <div> {currentProducts.map(product => ( <div key={product.id}> <p>{product.name}</p> <p>{product.price}</p> </div> ))} <button onClick={() => setCurrentPage(currentPage - 1)} disabled={currentPage === 1}>Previous</button> <button onClick={() => setCurrentPage(currentPage + 1)} disabled={endIndex >= products.length}>Next</button> </div> );
- 数据缓存:
- 对于已经获取过的商品数据进行缓存。可以使用
localStorage
(适用于较小数据量且不敏感数据)或在内存中进行缓存(例如使用一个对象来存储已请求的数据)。例如:
const productCache = {}; const getProducts = async () => { if (productCache['all']) { return productCache['all']; } const response = await fetch('/api/products'); const data = await response.json(); productCache['all'] = data; return data; };
- 对于已经获取过的商品数据进行缓存。可以使用