86 lines
2.1 KiB
JavaScript
86 lines
2.1 KiB
JavaScript
/**
|
|
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
*
|
|
* This source code is licensed under the MIT license found in the
|
|
* LICENSE file in the root directory of this source tree.
|
|
*
|
|
* @flow strict
|
|
* @format
|
|
*/
|
|
|
|
import invariant from 'invariant';
|
|
import * as React from 'react';
|
|
|
|
/**
|
|
* `setState` is called asynchronously, and should not rely on the value of
|
|
* `this.props` or `this.state`:
|
|
* https://reactjs.org/docs/state-and-lifecycle.html#state-updates-may-be-asynchronous
|
|
*
|
|
* SafePureComponent adds runtime enforcement, to catch cases where these
|
|
* variables are read in a state updater function, instead of the ones passed
|
|
* in.
|
|
*/
|
|
export default class StateSafePureComponent<
|
|
Props,
|
|
State: interface {},
|
|
> extends React.PureComponent<Props, State> {
|
|
_inAsyncStateUpdate = false;
|
|
|
|
constructor(props: Props) {
|
|
super(props);
|
|
this._installSetStateHooks();
|
|
}
|
|
|
|
setState(
|
|
partialState: ?($Shape<State> | ((State, Props) => ?$Shape<State>)),
|
|
callback?: () => mixed,
|
|
): void {
|
|
if (typeof partialState === 'function') {
|
|
super.setState((state, props) => {
|
|
this._inAsyncStateUpdate = true;
|
|
let ret;
|
|
try {
|
|
ret = partialState(state, props);
|
|
} catch (err) {
|
|
throw err;
|
|
} finally {
|
|
this._inAsyncStateUpdate = false;
|
|
}
|
|
return ret;
|
|
}, callback);
|
|
} else {
|
|
super.setState(partialState, callback);
|
|
}
|
|
}
|
|
|
|
_installSetStateHooks() {
|
|
const that = this;
|
|
let {props, state} = this;
|
|
|
|
Object.defineProperty(this, 'props', {
|
|
get() {
|
|
invariant(
|
|
!that._inAsyncStateUpdate,
|
|
'"this.props" should not be accessed during state updates',
|
|
);
|
|
return props;
|
|
},
|
|
set(newProps: Props) {
|
|
props = newProps;
|
|
},
|
|
});
|
|
Object.defineProperty(this, 'state', {
|
|
get() {
|
|
invariant(
|
|
!that._inAsyncStateUpdate,
|
|
'"this.state" should not be acceessed during state updates',
|
|
);
|
|
return state;
|
|
},
|
|
set(newState: State) {
|
|
state = newState;
|
|
},
|
|
});
|
|
}
|
|
}
|