cleanup: UNSAFE_componentWillReceiveProps -> modern lifecycles (React 19)
The 4 class components on UNSAFE_componentWillReceiveProps converted: - FromNow, FireStats: state is a pure mirror of props -> getDerivedStateFromProps - Fires: split the derived state (getDerivedStateFromProps) from the URL- canonicalization side effect (componentDidUpdate, guarded by prevProps) so the side effect never runs inside the pure gDSFP - SelectionMap: marker is also locally draggable, so gDSFP would clobber a drag -> componentDidUpdate guarded on a real center/distance value change (no clobber, no setState loop), merged with the existing fit() Browser-verified: /fires count, fire detail + FromNow, active-fire URL canonicalizes to /fire/archive/:id, home SelectionMap renders stably (no render loop). No UNSAFE_ warnings remain from our code. REST smoke byte-identical.
This commit is contained in:
parent
4ddaa0d8ec
commit
229b2cb233
4 changed files with 48 additions and 46 deletions
|
|
@ -18,13 +18,9 @@ class FromNow extends Component {
|
|||
};
|
||||
}
|
||||
|
||||
UNSAFE_componentWillReceiveProps(nextProps) {
|
||||
if (this.props.when !== nextProps.when) {
|
||||
// console.log(`Next when ${nextProps.when}`);
|
||||
this.setState({
|
||||
when: nextProps.when
|
||||
});
|
||||
}
|
||||
// state.when just mirrors props.when (was UNSAFE_componentWillReceiveProps)
|
||||
static getDerivedStateFromProps(props, state) {
|
||||
return props.when !== state.when ? { when: props.when } : null;
|
||||
}
|
||||
|
||||
shouldComponentUpdate(nextProps, nextState) {
|
||||
|
|
@ -36,7 +32,6 @@ class FromNow extends Component {
|
|||
}
|
||||
|
||||
render() {
|
||||
console.log(`Render from now ${this.state.when}`);
|
||||
return (
|
||||
<span data-toggle="tooltip" className="from-now" title={this.thatIs()}>{this.state.when}</span>
|
||||
);
|
||||
|
|
@ -49,9 +44,6 @@ FromNow.propTypes = {
|
|||
whenDate: PropTypes.instanceOf(Date)
|
||||
};
|
||||
|
||||
FromNow.defaultProps = {
|
||||
};
|
||||
|
||||
/*
|
||||
* const FromNowContainer = withTracker((props) => {
|
||||
*
|
||||
|
|
|
|||
|
|
@ -60,18 +60,22 @@ class SelectionMap extends Component {
|
|||
}
|
||||
}
|
||||
|
||||
UNSAFE_componentWillReceiveProps(nextProps) {
|
||||
const nextCenter = nextProps.center[0] ? nextProps.center : this.state.center;
|
||||
const nextMarker = nextProps.center[0] ? nextProps.center : this.state.marker;
|
||||
this.setState({
|
||||
center: nextCenter,
|
||||
marker: nextMarker,
|
||||
distance: nextProps.distance || this.state.distance
|
||||
});
|
||||
// this.fit();
|
||||
}
|
||||
|
||||
componentDidUpdate() {
|
||||
// Was UNSAFE_componentWillReceiveProps: pull center/distance from props into
|
||||
// state when they actually change. Done in componentDidUpdate (not
|
||||
// getDerivedStateFromProps) because the marker is also locally draggable, so
|
||||
// we must guard on a real value change to avoid clobbering a drag / looping.
|
||||
componentDidUpdate(prevProps) {
|
||||
const { center, distance } = this.props;
|
||||
const centerChanged = center[0] &&
|
||||
(center[0] !== this.state.center[0] || center[1] !== this.state.center[1]);
|
||||
const distanceChanged = distance && distance !== this.state.distance;
|
||||
if (centerChanged || distanceChanged) {
|
||||
this.setState({
|
||||
center: center[0] ? center : this.state.center,
|
||||
marker: center[0] ? center : this.state.marker,
|
||||
distance: distance || this.state.distance
|
||||
});
|
||||
}
|
||||
this.fit();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -37,18 +37,25 @@ class Fire extends React.Component {
|
|||
};
|
||||
}
|
||||
|
||||
UNSAFE_componentWillReceiveProps(nextProps) {
|
||||
if (this.props.when !== nextProps.when || this.props.loading !== nextProps.loading || this.props.notfound !== nextProps.notfound) {
|
||||
// console.log(`Next when ${nextProps.when}`);
|
||||
if (nextProps.fire && (nextProps.alert || nextProps.active || nextProps.fromHash)) {
|
||||
// change url to archive with new _id
|
||||
nextProps.history.replace(`/fire/archive/${hexId(nextProps.fire._id)}`);
|
||||
// state mirrors props purely for shouldComponentUpdate (render reads props
|
||||
// directly). Was the derived-state half of UNSAFE_componentWillReceiveProps.
|
||||
static getDerivedStateFromProps(props, state) {
|
||||
if (props.when !== state.when || props.loading !== state.loading || props.notfound !== state.notfound) {
|
||||
return { loading: props.loading, notfound: props.notfound, when: props.when };
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
componentDidUpdate(prevProps) {
|
||||
// side effect (must not run in getDerivedStateFromProps): once the fire is
|
||||
// resolved via alert/active/hash, canonicalize the URL to /fire/archive/:id
|
||||
if (prevProps.when !== this.props.when || prevProps.loading !== this.props.loading || prevProps.notfound !== this.props.notfound) {
|
||||
const {
|
||||
fire, alert, active, fromHash, history
|
||||
} = this.props;
|
||||
if (fire && (alert || active || fromHash)) {
|
||||
history.replace(`/fire/archive/${hexId(fire._id)}`);
|
||||
}
|
||||
this.setState({
|
||||
loading: nextProps.loading,
|
||||
notfound: nextProps.notfound,
|
||||
when: nextProps.when
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -17,17 +17,19 @@ class FireStats extends Component {
|
|||
};
|
||||
}
|
||||
|
||||
UNSAFE_componentWillReceiveProps(nextProps) {
|
||||
if (this.props.lastCheck !== nextProps.lastCheck ||
|
||||
this.props.lastFireDetected !== nextProps.lastFireDetected ||
|
||||
this.props.loadingAll !== nextProps.loadingAll
|
||||
// state mirrors props (was UNSAFE_componentWillReceiveProps)
|
||||
static getDerivedStateFromProps(props, state) {
|
||||
if (props.lastCheck !== state.lastCheck ||
|
||||
props.lastFireDetected !== state.lastFireDetected ||
|
||||
props.loadingAll !== state.loadingAll
|
||||
) {
|
||||
this.setState({
|
||||
lastFireDetected: nextProps.lastFireDetected,
|
||||
lastCheck: nextProps.lastCheck,
|
||||
loadingAll: nextProps.loadingAll
|
||||
});
|
||||
return {
|
||||
lastFireDetected: props.lastFireDetected,
|
||||
lastCheck: props.lastCheck,
|
||||
loadingAll: props.loadingAll
|
||||
};
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
shouldComponentUpdate(nextProps, nextState) {
|
||||
|
|
@ -54,7 +56,4 @@ FireStats.propTypes = {
|
|||
lastCheck: PropTypes.instanceOf(Date)
|
||||
};
|
||||
|
||||
FireStats.defaultProps = {
|
||||
};
|
||||
|
||||
export default withTranslation()(FireStats);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue