Skip to content

Commit 84de668

Browse files
committed
memoize more functions and props to prevent unnecessary reinit of webview
1 parent 707bd57 commit 84de668

1 file changed

Lines changed: 98 additions & 81 deletions

File tree

src/components/ChartUPlot.tsx

Lines changed: 98 additions & 81 deletions
Original file line numberDiff line numberDiff line change
@@ -242,6 +242,98 @@ const ChartUPlot = forwardRef<any, UPlotProps>(
242242
};
243243
}, []);
244244

245+
// memoized webview/view style to avoid recreating object on every render
246+
const memoizedContainerStyle = useMemo(() => {
247+
const base = style || {};
248+
return {
249+
...base,
250+
width: options?.width || base?.width || '100%',
251+
height: options?.height || base?.height || '100%',
252+
};
253+
}, [style, options?.width, options?.height]);
254+
255+
// memoized onLoadEnd handler for native WebView
256+
const handleLoadEnd = useCallback((): void => {
257+
// Use canonical dataRef when creating the native WebView chart
258+
dataRef.current = toPlainArrays(data as any[]) as number[][];
259+
createChart(options, dataRef.current, bgColor);
260+
261+
if (onLoad) {
262+
onLoad();
263+
}
264+
}, [data, options, bgColor, onLoad]);
265+
266+
// memoized onMessage handler for native WebView
267+
const handleMessage = useCallback(
268+
(payload: any): void => {
269+
if (onMessage) {
270+
onMessage(payload);
271+
return;
272+
}
273+
274+
let dataPayload;
275+
try {
276+
dataPayload = JSON.parse(payload.nativeEvent.data);
277+
} catch (e) {}
278+
279+
if (dataPayload) {
280+
if (dataPayload.type === 'Console') {
281+
console.info(`[Console] ${JSON.stringify(dataPayload.data)}`);
282+
} else {
283+
console.log(dataPayload);
284+
}
285+
}
286+
},
287+
[onMessage],
288+
);
289+
290+
// memoized ref callback for both web container and native WebView
291+
const setWebRef = useCallback(
292+
(r: any) => {
293+
const prevContainer = containerRef.current;
294+
const prevWeb = webref.current;
295+
const shouldReinit = Boolean(prevContainer && r && r !== prevWeb);
296+
297+
// update refs (allow clearing when r is null)
298+
containerRef.current = r;
299+
webref.current = r;
300+
301+
if (!r) return;
302+
303+
// On web, simply create chart when the DOM node appears
304+
if (Platform.OS === 'web') {
305+
createChart(options, data);
306+
return;
307+
}
308+
309+
// Native WebView: detect reinitialization and restore variables/data
310+
if (shouldReinit) {
311+
initialized.current = false;
312+
destroy(true);
313+
}
314+
315+
if (shouldReinit) {
316+
// console.log('Reinitializing WebView chart');
317+
318+
// re-add any variables that were set
319+
let injectedVars = '';
320+
Object.keys(variablesRef.current).forEach((key) => {
321+
injectedVars += `window.${key} = ${JSON.stringify(
322+
variablesRef.current[key],
323+
)};`;
324+
});
325+
webref.current.injectJavaScript(`
326+
${injectedVars}
327+
true;
328+
`);
329+
330+
// reinit using the canonical dataRef rather than the original prop
331+
createChart(options, dataRef.current, bgColor);
332+
}
333+
},
334+
[options, data, bgColor],
335+
);
336+
245337
// Keep canonical copy of incoming prop `data` (convert typed arrays to plain arrays).
246338
// Also mirror to window._data for native platforms when webref is available.
247339
useEffect(() => {
@@ -603,19 +695,9 @@ const ChartUPlot = forwardRef<any, UPlotProps>(
603695
if (Platform.OS === 'web') {
604696
return (
605697
<View
606-
ref={(r): any => {
607-
containerRef.current = r;
608-
webref.current = r;
609-
if (r) {
610-
createChart(options, data);
611-
}
612-
}}
698+
ref={setWebRef}
613699
onLayout={handleLayout}
614-
style={{
615-
...style,
616-
width: options?.width || style?.width || '100%',
617-
height: options?.height || style?.height || '100%',
618-
}}
700+
style={memoizedContainerStyle}
619701
/>
620702
);
621703
} else {
@@ -624,79 +706,14 @@ const ChartUPlot = forwardRef<any, UPlotProps>(
624706
{...webviewProps}
625707
originWhitelist={['*']}
626708
source={html}
627-
style={{
628-
...style,
629-
width: options?.width || style?.width || '100%',
630-
height: options?.height || style?.height || '100%',
631-
}}
709+
style={memoizedContainerStyle}
632710
scrollEnabled={false}
633-
onLoadEnd={(): void => {
634-
// Use canonical dataRef when creating the native WebView chart
635-
dataRef.current = toPlainArrays(data as any[]) as number[][];
636-
createChart(options, dataRef.current, bgColor);
637-
638-
if (onLoad) {
639-
onLoad();
640-
}
641-
}}
642-
ref={(r) => {
643-
if (r) {
644-
var shouldReinit = containerRef.current && r !== webref.current;
645-
646-
if (shouldReinit) {
647-
initialized.current = false;
648-
destroy(true);
649-
}
650-
651-
console.log('shouldReinit', shouldReinit);
652-
console.log('data', data);
653-
654-
containerRef.current = r;
655-
webref.current = r;
656-
657-
if (shouldReinit) {
658-
// re-add any variables that were set
659-
var injectedVars = '';
660-
Object.keys(variablesRef.current).forEach((key) => {
661-
injectedVars += `window.${key} = ${JSON.stringify(
662-
variablesRef.current[key],
663-
)};`;
664-
});
665-
webref.current.injectJavaScript(`
666-
${injectedVars}
667-
true;
668-
`);
669-
670-
// reinit using the canonical dataRef rather than the original prop
671-
createChart(options, dataRef.current, bgColor);
672-
}
673-
}
674-
}}
711+
onLoadEnd={handleLoadEnd}
712+
ref={setWebRef}
675713
onLayout={handleLayout}
676714
javaScriptEnabled={true}
677715
injectedJavaScript={`${injectedJavaScript}; true;`}
678-
onMessage={(payload): void => {
679-
// in webviewProps, if onMessage is provided, call it with the payload
680-
if (onMessage) {
681-
onMessage(payload);
682-
return;
683-
}
684-
685-
// Handle messages from the webview if needed
686-
// console.log('Message from webview:', event.nativeEvent.data);
687-
let dataPayload;
688-
try {
689-
dataPayload = JSON.parse(payload.nativeEvent.data);
690-
} catch (e) {}
691-
692-
if (dataPayload) {
693-
if (dataPayload.type === 'Console') {
694-
console.info(`[Console] ${JSON.stringify(dataPayload.data)}`);
695-
} else {
696-
console.log(dataPayload);
697-
}
698-
}
699-
}}
716+
onMessage={handleMessage}
700717
/>
701718
);
702719
}

0 commit comments

Comments
 (0)