React:浏览器窗口Resize时避免子组件重渲染的问题
解决方案:避免Resize时React子组件不必要重渲染
核心问题分析
你之前的useMemo未生效的原因有两点:
- 未用
React.memo包裹子组件,即使元素引用不变,子组件仍会随父组件重渲染 - 未缓存整个
columns数组,且在不同布局分支中重复创建子组件元素,导致元素引用每次都变化
步骤1:用React.memo包裹目标子组件
给PaymentOption(以及其他需要优化的子组件)添加React.memo,让它仅在props变化时重渲染:
// PaymentOption组件定义文件 import React from 'react'; const PaymentOption = React.memo((props) => { // 组件原有逻辑 }); export default PaymentOption;
步骤2:缓存子组件元素与columns数组
在父组件中,分别缓存每个子组件的元素实例,再缓存整个columns数组,确保仅当布局状态或子组件props变化时才更新:
const Parent = (props) => { // 1. 缓存单个子组件元素,依赖对应props const cachedCustomerInfo = useMemo(() => ( <CustomerInfo {...customerProps} /> ), [customerProps]); const cachedContactInfo = useMemo(() => ( <ContactInformation {...contactProps} /> ), [contactProps]); const cachedPaymentOption = useMemo(() => ( <PaymentOption {...paymentProps} /> ), [paymentProps]); const cachedAddressInfo = useMemo(() => ( <AddressInfo {...addressProps} /> ), [addressProps]); // 2. 缓存columns数组,依赖布局状态和缓存的子组件元素 const columns = useMemo(() => { if (isOneColumnLayout) { return [ <Fragment key="single-col"> {cachedCustomerInfo} {cachedContactInfo} {cachedPaymentOption} {cachedAddressInfo} </Fragment> ]; } else if (isTwoColumnLayout) { return [ <Fragment key="left-col"> {cachedCustomerInfo} {cachedContactInfo} {cachedPaymentOption} </Fragment>, <Fragment key="right-col"> {cachedAddressInfo} </Fragment> ]; } // 默认三栏布局 return [ <Fragment key="col-1"> {cachedCustomerInfo} </Fragment>, <Fragment key="col-2"> {cachedContactInfo} {cachedPaymentOption} </Fragment>, <Fragment key="col-3"> {cachedAddressInfo} </Fragment> ]; }, [isOneColumnLayout, isTwoColumnLayout, cachedCustomerInfo, cachedContactInfo, cachedPaymentOption, cachedAddressInfo]); return ( <Fragment> <FlexColumns columns={columns} /> </Fragment> ); };
步骤3:优化Resize事件监听(可选)
给resize事件添加防抖,减少父组件因窗口频繁调整而触发的重渲染次数:
const Parent = (props) => { const [windowWidth, setWindowWidth] = useState(window.innerWidth); useEffect(() => { // 防抖函数:200ms内仅执行一次 const debouncedResize = debounce(() => { setWindowWidth(window.innerWidth); }, 200); window.addEventListener('resize', debouncedResize); return () => window.removeEventListener('resize', debouncedResize); }, []); // 根据窗口宽度判断布局 const isOneColumnLayout = windowWidth < 768; const isTwoColumnLayout = windowWidth >= 768 && windowWidth < 1200; // ... 上述缓存逻辑 }; // 防抖工具函数 function debounce(func, delay) { let timeoutId; return (...args) => { clearTimeout(timeoutId); timeoutId = setTimeout(() => func.apply(this, args), delay); }; }
内容的提问来源于stack exchange,提问作者user26586245
相关产品推荐
相关产品推荐

