如何避免给memo包裹的Marker组件传带参匿名函数引发重渲染?
解决Marker组件不必要重渲染的问题
你的问题核心在于:父组件每次渲染时,都会为每个Marker创建新的匿名函数作为onPress prop,导致memo认为props发生变化,触发Marker重渲染。下面给你两种实用的解决思路:
方案一:拆分数据与回调(推荐)
不要直接传带参数的匿名函数,而是把marker.id作为单独的prop传给Marker,再把缓存后的selectMarker函数也传进去,让Marker内部自己组合调用逻辑。
父组件Map修改:
const Map = () => { // 用useCallback缓存selectMarker,依赖项填你实际用到的state/变量 const selectMarker = useCallback((markerId) => { // 这里写原来的selectMarker逻辑,比如更新选中状态等 console.log('选中标记:', markerId); }, []); // 例如如果用到了setSelectedId,就把setSelectedId加到依赖里 return ( <> {markers.map(marker => ( <Marker {...props} markerId={marker.id} onSelect={selectMarker} key={marker.id} // 记得加唯一key,这是React列表渲染的要求 /> ))} </> ) }
Marker组件修改:
// 保持用memo包裹 const Marker = memo(({ ...props, markerId, onSelect }) => { // 内部创建点击处理函数,这里不需要额外缓存,因为onSelect和markerId都是稳定的 const handlePress = () => { onSelect(markerId); }; // 原来的组件逻辑,比如渲染标记图标等 return <div onClick={handlePress} className="marker">...</div>; });
这样一来,传给Marker的onSelect是用useCallback缓存的稳定引用,markerId是值类型(字符串/数字),父组件重渲染时这两个prop都不会变,Marker就只会在真正需要的时候重渲染。
方案二:抽离子组件缓存回调
如果不想修改Marker的props结构,可以把单个Marker的渲染逻辑抽成一个独立的子组件,在子组件内部用useCallback创建稳定的onPress回调。
新增子组件MarkerItem:
// 用memo包裹子组件,确保只有props变化时才重渲染 const MarkerItem = memo(({ marker, ...props, selectMarker }) => { // 缓存点击回调,依赖是selectMarker和marker.id const handlePress = useCallback(() => { selectMarker(marker.id); }, [selectMarker, marker.id]); return <Marker {...props} onPress={handlePress} />; });
父组件Map修改:
const Map = () => { const selectMarker = useCallback((markerId) => { // 原来的逻辑 console.log('选中标记:', markerId); }, []); return ( <> {markers.map(marker => ( <MarkerItem marker={marker} {...props} selectMarker={selectMarker} key={marker.id} /> ))} </> ) }
这个方案的核心是利用子组件的memo,确保只有当marker.id或selectMarker变化时,才会重新创建handlePress,进而触发Marker的重渲染。
内容的提问来源于stack exchange,提问作者raouaoul
相关产品推荐
相关产品推荐

