1. 使用 useImperativeHandle
实现调用子组件方法
- 子组件(商品详情弹窗)代码
import React, { useRef, useImperativeHandle } from'react';
const ProductDetailPopup = React.forwardRef((props, ref) => {
const inputRef = useRef(null);
const stateRef = useRef({});
const reset = () => {
// 清除用户输入的临时数据,假设这里是清除 input 的值
if (inputRef.current) {
inputRef.current.value = '';
}
// 重置弹窗状态
stateRef.current = {};
};
useImperativeHandle(ref, () => ({
reset: reset
}));
return (
<div>
<input ref={inputRef} />
{/* 弹窗其他内容 */}
</div>
);
});
export default ProductDetailPopup;
- 父组件(商品列表页)代码
import React, { useRef } from'react';
import ProductDetailPopup from './ProductDetailPopup';
const ProductListPage = () => {
const popupRef = useRef(null);
const handleClick = () => {
if (popupRef.current) {
popupRef.current.reset();
}
};
return (
<div>
<button onClick={handleClick}>调用弹窗重置方法</button>
<ProductDetailPopup ref={popupRef} />
</div>
);
};
export default ProductListPage;
2. 处理可能出现的性能问题
- 避免不必要的渲染
- 在子组件中,使用
React.memo
包裹子组件,如果子组件是纯函数组件(不依赖于自身 state 且仅根据 props 渲染),这样可以避免在父组件渲染时,子组件进行不必要的重新渲染。例如:
const ProductDetailPopup = React.forwardRef((props, ref) => {
//...
});
export default React.memo(ProductDetailPopup);
- 防抖或节流
- 如果调用子组件重置方法的操作(如按钮点击)可能会频繁触发,可以使用防抖或节流技术。例如,使用
lodash
库中的 debounce
或 throttle
。
- 防抖示例:
import React, { useRef } from'react';
import { debounce } from 'lodash';
import ProductDetailPopup from './ProductDetailPopup';
const ProductListPage = () => {
const popupRef = useRef(null);
const handleClick = debounce(() => {
if (popupRef.current) {
popupRef.current.reset();
}
}, 300);
return (
<div>
<button onClick={handleClick}>调用弹窗重置方法</button>
<ProductDetailPopup ref={popupRef} />
</div>
);
};
export default ProductListPage;
- 这里使用
debounce
函数,在 300 毫秒内多次点击按钮,只会触发一次 reset
方法,避免了频繁调用带来的性能开销。
- 优化子组件内部逻辑
- 确保子组件内部的
reset
方法高效执行,避免在 reset
方法中进行复杂的、不必要的计算。例如,如果清除临时数据和重置状态涉及到多个步骤,尽量将这些步骤进行优化,避免重复计算或冗余操作。
- 如果子组件中有副作用操作(如 API 调用),可以使用
useEffect
配合 useRef
来控制副作用的触发频率,避免不必要的副作用执行。例如,在 reset
方法中触发了一个 API 调用,只有在必要时才重新调用这个 API。
import React, { useRef, useEffect } from'react';
const ProductDetailPopup = React.forwardRef((props, ref) => {
const inputRef = useRef(null);
const stateRef = useRef({});
const apiCallRef = useRef(false);
const reset = () => {
// 清除用户输入的临时数据,假设这里是清除 input 的值
if (inputRef.current) {
inputRef.current.value = '';
}
// 重置弹窗状态
stateRef.current = {};
apiCallRef.current = true;
};
useEffect(() => {
if (apiCallRef.current) {
// 进行 API 调用
apiCallRef.current = false;
}
}, [apiCallRef.current]);
useImperativeHandle(ref, () => ({
reset: reset
}));
return (
<div>
<input ref={inputRef} />
{/* 弹窗其他内容 */}
</div>
);
});
export default React.memo(ProductDetailPopup);