Skip to content

Commit bea68f9

Browse files
authored
fix: memoize context-values to avoid excessive re-renders (#287)
Add memoization to all context values used internally. Without the memoization, the context value of e.g. the GoogleMapsContext (used to retrieve the map-instance in the `useMap` hook) will register as changed every time the map-component re-renders, causing all children that use the context (for example via the `useMap` hook) to re-render as well. With the memoization in place, these unnecessary renders will no longer happen. fixes #285
1 parent 1a9deb0 commit bea68f9

3 files changed

Lines changed: 30 additions & 12 deletions

File tree

src/components/advanced-marker.tsx

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import React, {
66
useContext,
77
useEffect,
88
useImperativeHandle,
9+
useMemo,
910
useState
1011
} from 'react';
1112

@@ -147,14 +148,17 @@ export const AdvancedMarker = forwardRef(
147148
const {children} = props;
148149
const [marker, contentContainer] = useAdvancedMarker(props);
149150

151+
const advancedMarkerContextValue: AdvancedMarkerContextValue | null =
152+
useMemo(() => (marker ? {marker} : null), [marker]);
153+
150154
useImperativeHandle(ref, () => marker, [marker]);
151155

152156
if (!marker) {
153157
return null;
154158
}
155159

156160
return (
157-
<AdvancedMarkerContext.Provider value={{marker}}>
161+
<AdvancedMarkerContext.Provider value={advancedMarkerContextValue}>
158162
{contentContainer !== null && createPortal(children, contentContainer)}
159163
</AdvancedMarkerContext.Provider>
160164
);

src/components/api-provider.tsx

Lines changed: 22 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -188,17 +188,29 @@ export const APIProvider = (
188188
const {status, loadedLibraries, importLibrary} =
189189
useGoogleMapsApiLoader(loaderProps);
190190

191+
const contextValue: APIProviderContextValue = useMemo(
192+
() => ({
193+
mapInstances,
194+
addMapInstance,
195+
removeMapInstance,
196+
clearMapInstances,
197+
status,
198+
loadedLibraries,
199+
importLibrary
200+
}),
201+
[
202+
mapInstances,
203+
addMapInstance,
204+
removeMapInstance,
205+
clearMapInstances,
206+
status,
207+
loadedLibraries,
208+
importLibrary
209+
]
210+
);
211+
191212
return (
192-
<APIProviderContext.Provider
193-
value={{
194-
mapInstances,
195-
addMapInstance,
196-
removeMapInstance,
197-
clearMapInstances,
198-
status,
199-
loadedLibraries,
200-
importLibrary
201-
}}>
213+
<APIProviderContext.Provider value={contextValue}>
202214
{children}
203215
</APIProviderContext.Provider>
204216
);

src/components/map/index.tsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -172,6 +172,8 @@ export const Map = (props: PropsWithChildren<MapProps>) => {
172172
[style, isDeckGlControlled]
173173
);
174174

175+
const contextValue: GoogleMapsContextValue = useMemo(() => ({map}), [map]);
176+
175177
if (loadingStatus === APILoadingStatus.AUTH_FAILURE) {
176178
return (
177179
<div
@@ -190,7 +192,7 @@ export const Map = (props: PropsWithChildren<MapProps>) => {
190192
className={className}
191193
{...(id ? {id} : {})}>
192194
{map ? (
193-
<GoogleMapsContext.Provider value={{map}}>
195+
<GoogleMapsContext.Provider value={contextValue}>
194196
{children}
195197
</GoogleMapsContext.Provider>
196198
) : null}

0 commit comments

Comments
 (0)