Background:
LightLineChart ui runs several functions in order to interpolate points and make a path to SVG format.
This requires multiple iterations which gives a burden to rendering process.
Problem:
The codes for interpolation and SVG path drawing, will be continuously called on any of the props changes or parent component's state changes.
const minValue = Math.min(...data) - lineWidth - padding;
const maxValue = Math.max(...data) + lineWidth + padding;
const xStep = width / (data.length - 1);
const yStep = height / (maxValue - minValue);
let pathData;
let colorPathData;
if (curve) {
const points = catmullRom2bezier(data, minValue, xStep, yStep, height)
function makePath(points) {
var result = "M" + points[0][0].x + "," + points[0][0].y + " ";
for (var i = 0; i < points.length; i++) {
result += "C" + points[i][0].x + "," + points[i][0].y + " " + points[i][1].x + "," + points[i][1].y + " " + points[i][2].x + "," + points[i][2].y + " ";
}
return result;
}
function makeColorPath(points) {
var result = "M" + points[0][0].x + "," + points[0][0].y + " ";
for (var i = 0; i < points.length; i++) {
result += "C" + points[i][0].x + "," + points[i][0].y + " " + points[i][1].x + "," + points[i][1].y + " " + points[i][2].x + "," + points[i][2].y + " ";
}
result += "L" + points[points.length-1][2].x + "," + height + " "
result += "L" + 0 + "," + height + "z";
return result;
}
pathData = makePath(points)
colorPathData = makeColorPath(points)
} else {
const points = data.map((value, index) => ({
x: index * xStep,
y: height - (value - minValue) * yStep,
}));
pathData = `M${points.map(p => `${p.x},${p.y}`).join(' L')}`;
colorPathData = `M${points.map(p => `${p.x},${p.y}`).join(' L')}` + "L" + points[points.length-1].x + "," + height + " " + "L" + 0 + "," + height + "z";
}
Solution:
We can optimize this code with "useMemo" hook and "memo" HOC from React.
Caching results with useMemo
useMemo(() => {
const minValue = Math.min(...data) - lineWidth - padding;
const maxValue = Math.max(...data) + lineWidth + padding;
const xStep = width / (data.length - 1);
const yStep = height / (maxValue - minValue);
if (curve) {
const points = catmullRom2bezier(data, minValue, xStep, yStep, height);
function makePath(points) {
var result = "M" + points[0][0].x + "," + points[0][0].y + " ";
for (var i = 0; i < points.length; i++) {
result +=
"C" +
points[i][0].x +
"," +
points[i][0].y +
" " +
points[i][1].x +
"," +
points[i][1].y +
" " +
points[i][2].x +
"," +
points[i][2].y +
" ";
}
return result;
}
function makeColorPath(points) {
var result = "M" + points[0][0].x + "," + points[0][0].y + " ";
for (var i = 0; i < points.length; i++) {
result +=
"C" +
points[i][0].x +
"," +
points[i][0].y +
" " +
points[i][1].x +
"," +
points[i][1].y +
" " +
points[i][2].x +
"," +
points[i][2].y +
" ";
}
result += "L" + points[points.length - 1][2].x + "," + height + " ";
result += "L" + 0 + "," + height + "z";
return result;
}
setPathData(makePath(points));
setColorPathData(makeColorPath(points));
} else {
const points = data.map((value, index) => ({
x: index * xStep,
y: height - (value - minValue) * yStep
}));
const pathData_ = `M${points.map((p) => `${p.x},${p.y}`).join(" L")}`;
setPathData(pathData_);
const colorPathData_ =
`M${points.map((p) => `${p.x},${p.y}`).join(" L")}` +
"L" +
points[points.length - 1].x +
"," +
height +
" " +
"L" +
0 +
"," +
height +
"z";
setColorPathData(colorPathData_);
}
}, [data, width, height, lineWidth, padding, curve]);
Skipping re-rendering when no props change
export default memo(LightLineChart);
'Front-End > React' 카테고리의 다른 글
[React] 디바운스로 추천 검색 기능 구현하기 (0) | 2023.11.07 |
---|---|
[React] textarea input에서 shift+enter로 줄 바꾸기 (0) | 2023.07.03 |
[React] React Fiber Reconciler (0) | 2023.06.16 |
[React] lambda-client request 취소하기 (0) | 2023.05.15 |
[React] Auth0로 authentication처리 (0) | 2023.05.15 |