React函数组件如何基于状态变化控制重渲染、避免子组件不必要渲染
解决方案
问题根因
React.memo失效的核心原因是:每次Shop组件重渲染时,addProductHandler都会生成新的函数引用,导致传入Product的props发生变化,memo判定需要重渲染,和Shop的内部状态变更本身没有直接关系。- 仅把
products作为useMemo依赖时,addProductHandler捕获的是首次渲染的cart闭包,永远指向初始的空数组,因此新增购物车逻辑会异常。
具体实现步骤
1. 用useCallback稳定事件处理函数引用
修改addProductHandler,使用setCart的函数式更新语法,避免依赖外部cart变量,再用useCallback包裹,让函数引用在组件生命周期内保持稳定:
import React, { useState, useCallback } from 'react'; import fakeData from '../../fakeData'; import Product from '../Product/Product'; const Shop = () => { console.log('[Shop.js] rendered') const first10 = fakeData.slice(0, 10); const [products, setProducts] = useState(first10); const [cart, setCart] = useState([]); // 用useCallback + 函数式更新稳定引用 const addProductHandler = useCallback((product) => { setCart(prevCart => [...prevCart, product]); }, []); // 无外部依赖,引用永远不变 return ( <div className="shop-container"> <div className="product-container"> {products.map(prod => ( <Product key={prod.id} product={prod} addProductHandler={addProductHandler} /> ))} </div> <div className="cart-container"> <h3>this is cart</h3> <h5>Order Summary: {cart.length}</h5> </div> </div> ); }; export default Shop;
2. 给Product组件包裹React.memo
在Product组件的导出位置添加memo包裹,现在传入的product和addProductHandler都是稳定引用,只有product本身发生变化时,Product才会重渲染:
// Product.js 文件 import React, { memo } from 'react'; const Product = ({ product, addProductHandler }) => { console.log('[Product.js] rendered', product.id); // 组件原有逻辑 return ( <div> {/* 产品展示逻辑 */} <button onClick={() => addProductHandler(product)}>加入购物车</button> </div> ) } // 导出时用memo包裹 export default memo(Product);
自定义渲染控制
如果产品对象每次都会生成新的引用(比如接口请求返回新对象),可以给memo传入第二个自定义比较函数,实现和shouldComponentUpdate同等的灵活控制:
export default memo(Product, (prevProps, nextProps) => { // 自定义比较逻辑,返回true表示不需要重渲染,返回false表示需要重渲染 return prevProps.product.id === nextProps.product.id && prevProps.product.price === nextProps.product.price && prevProps.product.name === nextProps.product.name // 其他需要比较的产品属性 })
内容的提问来源于stack exchange,提问作者Zepticona
相关产品推荐
相关产品推荐

