DateTime: avoid unnecessary update (#6110)

## Issue
Part of `5834 Performance investigation`

In a homepage with 120 tiles, the lists get rendered 3 times during initial update. The sub-components are updating recursively (will investigate), so instead of 120 DateTime renders, we have 1000+ renders.

The resolved DateTime string for `timeAgo` rarely changes, and even if the string was "a few seconds ago", there's no real need to constantly update it.

## Change
Require a minimum 1-minute delta when deciding whether the component should update. Clients can change this value as needed.

## Test
- [x] Verified `shouldComponentUpdate` doesn't end up taking more time than not having it (it's in micro-second range, compared to the millisecond render).
- [x] Profiler showed no significant improvement for low number of DateTime components, but for the 120 DateTime case, almost 1/4 of a second is saved.
This commit is contained in:
infinite-persistence 2021-05-25 06:29:58 +08:00 committed by GitHub
parent 9e13596104
commit cded632fd2
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23

View file

@ -2,15 +2,29 @@
import React from 'react'; import React from 'react';
import moment from 'moment'; import moment from 'moment';
const DEFAULT_MIN_UPDATE_DELTA_MS = 60 * 1000;
type Props = { type Props = {
date?: any, date?: any,
timeAgo?: boolean, timeAgo?: boolean,
formatOptions: {}, formatOptions?: {},
show?: string, show?: string,
clock24h: boolean, clock24h?: boolean,
minUpdateDeltaMs?: number,
}; };
class DateTime extends React.PureComponent<Props> { type State = {
lastRenderTime: Date,
};
class DateTime extends React.Component<Props, State> {
constructor(props: Props) {
super(props);
this.state = {
lastRenderTime: new Date(),
};
}
static SHOW_DATE = 'date'; static SHOW_DATE = 'date';
static SHOW_TIME = 'time'; static SHOW_TIME = 'time';
@ -45,6 +59,38 @@ class DateTime extends React.PureComponent<Props> {
return __(strId, { duration }); return __(strId, { duration });
} }
shouldComponentUpdate(nextProps: Props): boolean {
if (
moment(this.props.date).diff(moment(nextProps.date)) !== 0 ||
this.props.clock24h !== nextProps.clock24h ||
this.props.timeAgo !== nextProps.timeAgo ||
this.props.minUpdateDeltaMs !== nextProps.minUpdateDeltaMs ||
this.props.show !== nextProps.show
) {
return true;
}
if (this.props.timeAgo && nextProps.timeAgo) {
const minUpdateDeltaMs = this.props.minUpdateDeltaMs || DEFAULT_MIN_UPDATE_DELTA_MS;
const prev = moment(this.state.lastRenderTime);
const curr = moment(new Date());
const deltaMs = curr.diff(prev);
if (deltaMs > minUpdateDeltaMs) {
return true;
}
}
return false;
}
componentDidUpdate() {
const { timeAgo } = this.props;
if (timeAgo) {
this.setState({ lastRenderTime: new Date() });
}
}
render() { render() {
const { date, timeAgo, show, clock24h } = this.props; const { date, timeAgo, show, clock24h } = this.props;