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:
vjrj 2026-07-21 14:03:44 +02:00
parent 4ddaa0d8ec
commit 229b2cb233
4 changed files with 48 additions and 46 deletions

View file

@ -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);