Skip to content

Commit a52bc9b

Browse files
committed
fix rerendering, esm
1 parent a28a5d4 commit a52bc9b

File tree

9 files changed

+270
-186
lines changed

9 files changed

+270
-186
lines changed

demo/app/(tabs)/index.tsx

Lines changed: 23 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,23 @@
1-
import { useEffect, useRef, useState } from 'react';
1+
import { useEffect, useRef, useState, useMemo } from 'react';
22
import { Platform, StyleSheet, SafeAreaView, Text } from 'react-native';
33

4-
import { ChartUPlot } from 'uplot-react-native';
4+
import ChartUPlot from 'uplot-react-native';
55

66
var data = [[Date.now()], [Math.random() * 100]];
7+
var count = 1;
8+
9+
var options = {
10+
id: 'chart',
11+
width: 300,
12+
height: 300,
13+
scales: { x: { time: true } },
14+
series: [{ label: 'Time' }, { label: 'Value', stroke: 'blue', width: 2 }],
15+
axes: [{ scale: 'x' }, {}],
16+
};
17+
var style = {
18+
width: 300,
19+
height: 300,
20+
};
721

822
export default function HomeScreen() {
923
// create ref for chart
@@ -12,9 +26,12 @@ export default function HomeScreen() {
1226

1327
useEffect(() => {
1428
setInterval(() => {
15-
// chartRef.current?.pushData([Date.now(), Math.random() * 100]);
16-
// setNDataPoint((prev) => prev + 1);
17-
}, 33);
29+
chartRef.current?.pushData([Date.now(), Math.random() * 100]);
30+
count++;
31+
}, 1000);
32+
setInterval(() => {
33+
setNDataPoint(count);
34+
}, 1000);
1835
}, []);
1936

2037
return (
@@ -39,25 +56,7 @@ export default function HomeScreen() {
3956
<Text style={{ fontSize: 16, marginBottom: 16 }}>
4057
{nDataPoint} data points
4158
</Text>
42-
<ChartUPlot
43-
data={data}
44-
options={{
45-
id: 'chart',
46-
width: 300,
47-
height: 300,
48-
scales: { x: { time: true } },
49-
series: [
50-
{ label: 'Time' },
51-
{ label: 'Value', stroke: 'blue', width: 2 },
52-
],
53-
axes: [{ scale: 'x' }, {}],
54-
}}
55-
style={{
56-
width: 300,
57-
height: 300,
58-
}}
59-
ref={chartRef}
60-
/>
59+
<ChartUPlot data={data} options={options} style={style} ref={chartRef} />
6160
</SafeAreaView>
6261
);
6362
}

demo/yarn.lock

Lines changed: 134 additions & 134 deletions
Large diffs are not rendered by default.

package.json

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,17 +11,17 @@
1111
"type": "git",
1212
"url": "git+https://github.com/murphycj/uplot-react-native.git"
1313
},
14+
"type": "module",
1415
"main": "dist/index.js",
1516
"types": "dist/index",
1617
"files": [
1718
"dist"
1819
],
1920
"scripts": {
20-
"build": "tsc && node scripts/replace-uplot-assets.js",
21-
"ci": "npm run build && npm run check-format && npm run check-exports",
21+
"build": "tsc && node scripts/replace-uplot-assets.cjs",
22+
"ci": "npm run build && npm run check-format",
2223
"format": "prettier --write .",
2324
"check-format": "prettier --check .",
24-
"check-exports": "attw --pack .",
2525
"local-release": "changeset version && changeset publish",
2626
"prepublishOnly": "npm run ci"
2727
},

scripts/replace-uplot-assets.cjs

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
#!/usr/bin/env node
2+
const fs = require('fs');
3+
const path = require('path');
4+
5+
const projectRoot = path.resolve(__dirname, '..');
6+
const htmlPath = path.join(projectRoot, 'src', 'components', 'uplot.html');
7+
const htmlPathOut = path.join(projectRoot, 'dist', 'components', 'uplot.html');
8+
const cssPath = path.join(
9+
projectRoot,
10+
'node_modules',
11+
'uplot',
12+
'dist',
13+
'uPlot.min.css',
14+
);
15+
const jsPath = path.join(
16+
projectRoot,
17+
'node_modules',
18+
'uplot',
19+
'dist',
20+
'uPlot.iife.min.js',
21+
);
22+
23+
async function main() {
24+
try {
25+
const [html, css, js] = await Promise.all([
26+
fs.promises.readFile(htmlPath, 'utf8'),
27+
fs.promises.readFile(cssPath, 'utf8'),
28+
fs.promises.readFile(jsPath, 'utf8'),
29+
]);
30+
31+
const cssTag = `<style>\n${css}\n</style>`;
32+
const jsTag = `<script>\n${js}\n</script>`;
33+
34+
let replaced = html
35+
.replace(/'\{\{UPLOT_CSS\}\}'/, cssTag)
36+
.replace(/'\{\{UPLOT_JS\}\}'/, jsTag);
37+
38+
await fs.promises.writeFile(htmlPathOut, replaced, 'utf8');
39+
console.log('uplot assets injected into uplot.html');
40+
} catch (err) {
41+
console.error('Error injecting uplot assets:', err);
42+
process.exit(1);
43+
}
44+
}
45+
46+
main();

src/components/ChartUPlot.tsx

Lines changed: 58 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,8 @@ import { WebView } from 'react-native-webview';
99

1010
var isWeb = Platform.OS === 'web';
1111

12-
const html = require('./uplot.html');
12+
// const html = require('./uplot.html');
13+
import html from './uplot.html';
1314
import 'uplot/dist/uPlot.min.css';
1415

1516
var uPlot: any = null;
@@ -33,29 +34,62 @@ const ChartUPlot = forwardRef<any, UPlotProps>(
3334
let webref: any = useRef(null);
3435
const uplotInstance = useRef<any>(null);
3536
const dataRef = useRef(data);
37+
const initialized = useRef(false);
38+
39+
const guardAndCreateJS = `
40+
(function() {
41+
if (window.__CHART_CREATED__) return;
42+
window.__CHART_CREATED__ = true;
43+
44+
// stash your data and options on window
45+
window._data = ${JSON.stringify(data)};
46+
window._opts = ${JSON.stringify({
47+
...options,
48+
width: style?.width || width,
49+
height: style?.height || height,
50+
})};
51+
52+
// now actually construct uPlot
53+
window._chart = new uPlot(window._opts, window._data, document.getElementById('chart'));
54+
})();
55+
true;
56+
`;
3657

3758
// eslint-disable-next-line @typescript-eslint/no-explicit-any
3859
const createChart = useCallback((opts: any, data: number[][]): void => {
3960
// Subtracting height of u-title and u-legend and some more?
4061
opts.height = style?.height || 200;
4162
opts.width = style?.width || width;
4263

64+
if (initialized.current) {
65+
// If already initialized, just set the data
66+
// setData(data);
67+
return;
68+
}
69+
4370
if (isWeb) {
4471
uplotInstance.current = new uPlot(opts, data, webref);
4572
} else {
4673
webref?.injectJavaScript(
47-
`let data = ${JSON.stringify(data)}; let uplot = new uPlot(${JSON.stringify(opts)}, data, document.getElementById("chart"));true;`,
74+
`
75+
window._data = ${JSON.stringify(data)};
76+
window._opts = ${JSON.stringify(opts)};
77+
window._chart = new uPlot(window._opts, window._data, document.getElementById("chart"));
78+
true;`,
4879
);
4980
}
81+
initialized.current = true;
5082
}, []);
5183

5284
const setData = useCallback((newData: number[][]): void => {
5385
if (isWeb) {
5486
uplotInstance.current?.setData(newData);
5587
} else {
56-
webref?.injectJavaScript(
57-
`uplot.setData(${JSON.stringify(newData)});true;`,
58-
);
88+
webref?.injectJavaScript(`
89+
window._data = ${JSON.stringify(newData)};
90+
window._chart.setData(window._data);
91+
true;
92+
`);
5993
}
6094
}, []);
6195

@@ -72,10 +106,18 @@ const ChartUPlot = forwardRef<any, UPlotProps>(
72106
} else {
73107
webref?.injectJavaScript(`
74108
var item = ${JSON.stringify(item)};
109+
110+
if (!window._data) {
111+
window._data = [];
112+
for (let i = 0; i < item.length; i++) {
113+
window._data.push([]);
114+
}
115+
}
116+
75117
for (let i = 0; i < item.length; i++) {
76-
data[i].push(item[i]);
118+
window._data[i].push(item[i]);
77119
}
78-
uplot.setData(data);true;`);
120+
window._chart.setData(window._data);true;`);
79121
}
80122
}, []);
81123

@@ -84,9 +126,9 @@ const ChartUPlot = forwardRef<any, UPlotProps>(
84126
if (isWeb) {
85127
uplotInstance.current?.setScale(axis, options);
86128
} else {
87-
webref?.injectJavaScript(
88-
`uplot.setScale(${JSON.stringify(axis)}, ${JSON.stringify(options)});true;`,
89-
);
129+
webref?.injectJavaScript(`
130+
window._chart.setScale(${JSON.stringify(axis)}, ${JSON.stringify(options)});true;
131+
`);
90132
}
91133
}, []);
92134

@@ -96,7 +138,7 @@ const ChartUPlot = forwardRef<any, UPlotProps>(
96138
uplotInstance.current?.setSize(width, height);
97139
} else {
98140
webref?.injectJavaScript(
99-
`uplot.setSize(${JSON.stringify(width)}, ${JSON.stringify(height)});true;`,
141+
`window._chart.setSize(${JSON.stringify(width)}, ${JSON.stringify(height)});true;`,
100142
);
101143
}
102144
}, []);
@@ -106,7 +148,7 @@ const ChartUPlot = forwardRef<any, UPlotProps>(
106148
if (isWeb) {
107149
uplotInstance.current?.destroy();
108150
} else {
109-
webref?.injectJavaScript('uplot.destroy();true;');
151+
webref?.injectJavaScript('window._chart.destroy();true;');
110152
}
111153
}, []);
112154

@@ -145,22 +187,16 @@ const ChartUPlot = forwardRef<any, UPlotProps>(
145187
}}
146188
scrollEnabled={false}
147189
onLoadEnd={(): void => {
148-
console.log('WebView loaded');
149-
150-
createChart(options, data);
190+
webref.injectJavaScript(guardAndCreateJS);
151191
}}
152-
ref={(r): any => {
192+
ref={(r) => {
153193
webref = r;
154-
if (r) {
155-
console.log('WebView ref set');
156-
157-
createChart(options, data);
158-
}
159194
}}
195+
javaScriptEnabled={true}
160196
/>
161197
);
162198
}
163199
},
164200
);
165201

166-
export default ChartUPlot;
202+
export default React.memo(ChartUPlot);

src/index.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1 @@
1-
export { default as ChartUPlot } from './components/ChartUPlot';
2-
export * from './components/ChartUPlot';
1+
export { default } from './components/ChartUPlot';

src/types/html.d.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
declare module '*.html' {
2+
const content: WebViewSource;
3+
export default content;
4+
}

tsconfig.esm.json

Whitespace-only changes.

tsconfig.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
"declaration": true,
66
"esModuleInterop": true,
77
"target": "ES5",
8-
"module": "CommonJS",
8+
"module": "esnext",
99
"outDir": "dist",
1010
"rootDir": "src",
1111
"skipLibCheck": true,

0 commit comments

Comments
 (0)