mirror of
https://github.com/shlinkio/shlink-web-client.git
synced 2024-12-23 01:20:24 +03:00
Memoized DefaultChart to make sure it does not change unless its props also change
This commit is contained in:
parent
039a56f410
commit
58ee123cef
3 changed files with 26 additions and 16 deletions
|
@ -14,5 +14,8 @@
|
||||||
"process": true,
|
"process": true,
|
||||||
"setImmediate": true
|
"setImmediate": true
|
||||||
},
|
},
|
||||||
"ignorePatterns": ["src/service*.ts"]
|
"ignorePatterns": ["src/service*.ts"],
|
||||||
|
"rules": {
|
||||||
|
"complexity": "off"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -43,7 +43,7 @@ const toDate = (date?: string | Date): Date | undefined => typeof date === 'stri
|
||||||
export const ShortUrlForm = (
|
export const ShortUrlForm = (
|
||||||
TagsSelector: FC<TagsSelectorProps>,
|
TagsSelector: FC<TagsSelectorProps>,
|
||||||
DomainSelector: FC<DomainSelectorProps>,
|
DomainSelector: FC<DomainSelectorProps>,
|
||||||
): FC<ShortUrlFormProps> => ({ mode, saving, onSave, initialState, selectedServer }) => { // eslint-disable-line complexity
|
): FC<ShortUrlFormProps> => ({ mode, saving, onSave, initialState, selectedServer }) => {
|
||||||
const [ shortUrlData, setShortUrlData ] = useState(initialState);
|
const [ shortUrlData, setShortUrlData ] = useState(initialState);
|
||||||
const isEdit = mode === 'edit';
|
const isEdit = mode === 'edit';
|
||||||
const changeTags = (tags: string[]) => setShortUrlData({ ...shortUrlData, tags: tags.map(normalizeTag) });
|
const changeTags = (tags: string[]) => setShortUrlData({ ...shortUrlData, tags: tags.map(normalizeTag) });
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { useState } from 'react';
|
import { useState, memo } from 'react';
|
||||||
import { Doughnut, Bar } from 'react-chartjs-2';
|
import { Doughnut, Bar } from 'react-chartjs-2';
|
||||||
import { keys, values } from 'ramda';
|
import { keys, values } from 'ramda';
|
||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
|
@ -53,7 +53,7 @@ const generateChartDatasets = (
|
||||||
borderWidth: 2,
|
borderWidth: 2,
|
||||||
};
|
};
|
||||||
|
|
||||||
if (!isBarChart) {
|
if (!isBarChart || highlightedData.every((value) => value === 0)) {
|
||||||
return [ mainDataset ];
|
return [ mainDataset ];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -102,7 +102,7 @@ const chartElementAtEvent = (
|
||||||
|
|
||||||
const statsAreDefined = (stats: Stats | undefined): stats is Stats => !!stats && Object.keys(stats).length > 0;
|
const statsAreDefined = (stats: Stats | undefined): stats is Stats => !!stats && Object.keys(stats).length > 0;
|
||||||
|
|
||||||
const DefaultChart = (
|
const DefaultChart = memo((
|
||||||
{ isBarChart = false, stats, max, highlightedStats, highlightedLabel, onClick }: DefaultChartProps,
|
{ isBarChart = false, stats, max, highlightedStats, highlightedLabel, onClick }: DefaultChartProps,
|
||||||
) => {
|
) => {
|
||||||
const Component = isBarChart ? Bar : Doughnut;
|
const Component = isBarChart ? Bar : Doughnut;
|
||||||
|
@ -150,20 +150,27 @@ const DefaultChart = (
|
||||||
const chartData = generateChartData(isBarChart, labels, data, highlightedData, highlightedLabel);
|
const chartData = generateChartData(isBarChart, labels, data, highlightedData, highlightedLabel);
|
||||||
const height = determineHeight(isBarChart, labels);
|
const height = determineHeight(isBarChart, labels);
|
||||||
|
|
||||||
|
const renderChartComponent = (customKey: string) => (
|
||||||
|
<Component
|
||||||
|
ref={(element) => {
|
||||||
|
setChartRef(element ?? undefined);
|
||||||
|
}}
|
||||||
|
key={`${height}_${customKey}`}
|
||||||
|
data={chartData}
|
||||||
|
options={options}
|
||||||
|
height={height}
|
||||||
|
getElementAtEvent={chartElementAtEvent(labels, onClick) as any}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
|
||||||
// Provide a key based on the height, so that every time the dataset changes, a new chart is rendered
|
// Provide a key based on the height, so that every time the dataset changes, a new chart is rendered
|
||||||
return (
|
return (
|
||||||
<div className="row">
|
<div className="row">
|
||||||
<div className={classNames('col-sm-12', { 'col-md-7': !isBarChart })}>
|
<div className={classNames('col-sm-12', { 'col-md-7': !isBarChart })}>
|
||||||
<Component
|
{/* It's VERY IMPORTANT to render two different components here, as one has 1 dataset and the other has 2 */}
|
||||||
ref={(element) => {
|
{/* Using the same component causes a crash when switching from 1 to 2 datasets, and then back to 1 dataset */}
|
||||||
setChartRef(element ?? undefined);
|
{highlightedStats !== undefined && renderChartComponent('with_stats')}
|
||||||
}}
|
{highlightedStats === undefined && renderChartComponent('without_stats')}
|
||||||
key={height}
|
|
||||||
data={chartData}
|
|
||||||
options={options}
|
|
||||||
height={height}
|
|
||||||
getElementAtEvent={chartElementAtEvent(labels, onClick) as any}
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
{!isBarChart && (
|
{!isBarChart && (
|
||||||
<div className="col-sm-12 col-md-5">
|
<div className="col-sm-12 col-md-5">
|
||||||
|
@ -172,6 +179,6 @@ const DefaultChart = (
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
});
|
||||||
|
|
||||||
export default DefaultChart;
|
export default DefaultChart;
|
||||||
|
|
Loading…
Reference in a new issue