Upgrade React-Redux (2nd attempt)

Summary:
- Update and include `react-redux` to Greenkeeper
- Remove legacy context which is used to access `store`
- Export `store` directly to use instead of legacy context

Note:
1st attempt: D18169584 -> got backouted in D18203354

Reviewed By: jknoxville

Differential Revision: D18297298

fbshipit-source-id: fd968f1b211eabb094113a0b35e84305f70117fc
This commit is contained in:
Chaiwat Ekkaewnumchai
2019-11-04 07:42:39 -08:00
committed by Facebook Github Bot
parent 61d4e0c6a5
commit c1130a167b
8 changed files with 264 additions and 253 deletions

View File

@@ -72,7 +72,7 @@
"@types/lodash.isequal": "^4.5.5",
"@types/react": "16.9.11",
"@types/react-dom": "^16.9.2",
"@types/react-redux": "^7.1.1",
"@types/react-redux": "^7.1.5",
"@types/react-virtualized-auto-sizer": "^1.0.0",
"@types/react-window": "^1.8.1",
"@types/redux-persist": "^4.3.1",
@@ -155,7 +155,7 @@
"react-devtools-core": "^4.0.6",
"react-dom": "^16.11.0",
"react-emotion": "^9.2.6",
"react-redux": "^5.0.7",
"react-redux": "^7.1.1",
"react-test-renderer": "^16.11.0",
"react-transition-group": "^4.3.0",
"react-virtualized-auto-sizer": "^1.0.2",
@@ -179,12 +179,10 @@
},
"greenkeeper": {
"ignore": [
"@types/react-redux",
"electron",
"electron-builder",
"emotion",
"react-emotion",
"react-redux",
"tmp"
]
},

View File

@@ -22,10 +22,10 @@ import {
colors,
} from 'flipper';
import {FlipperDevicePlugin, BaseAction} from './plugin';
import {connect} from 'react-redux';
import {connect, ReactReduxContext} from 'react-redux';
import {store} from './init';
import React, {Component, Fragment} from 'react';
import {clipboard} from 'electron';
import PropTypes from 'prop-types';
import {
PluginNotification,
clearAllNotifications,
@@ -49,30 +49,30 @@ export default class Notifications<
static icon = 'bell';
static keyboardActions: KeyboardActions = ['clear'];
static contextTypes = {
store: PropTypes.object.isRequired,
};
static supportsDevice() {
return false;
}
onKeyboardAction = (action: string) => {
if (action === 'clear') {
this.onClear();
this.onClear(store)();
}
};
onClear = () => {
(this.context.store as Store<StoreState>).dispatch(clearAllNotifications());
onClear = (store: Store<StoreState>) => () => {
store.dispatch(clearAllNotifications());
};
render() {
const {blacklistedPlugins, blacklistedCategories} = (this.context
.store as Store<StoreState>).getState().notifications;
return (
<ReactReduxContext.Consumer>
{({store}) => {
const {blacklistedPlugins, blacklistedCategories} = (store as Store<
StoreState
>).getState().notifications;
return (
<ConnectedNotificationsTable
onClear={this.onClear}
onClear={this.onClear(store)}
selectedID={this.props.deepLinkPayload}
onSelectPlugin={this.props.selectPlugin}
logger={this.props.logger}
@@ -90,11 +90,14 @@ export default class Notifications<
]}
actions={
<Fragment>
<Button onClick={this.onClear}>Clear</Button>
<Button onClick={this.onClear(store)}>Clear</Button>
</Fragment>
}
/>
);
}}
</ReactReduxContext.Consumer>
);
}
}

View File

@@ -8,13 +8,12 @@
*/
import {Button, styled} from 'flipper';
import {connect} from 'react-redux';
import {connect, ReactReduxContext} from 'react-redux';
import {spawn} from 'child_process';
import {dirname} from 'path';
import {selectDevice, preferDevice} from '../reducers/connections';
import {default as which} from 'which';
import {showOpenDialog} from '../utils/exportData';
import PropTypes from 'prop-types';
import BaseDevice from '../devices/BaseDevice';
import React, {Component} from 'react';
import {State} from '../reducers';
@@ -38,10 +37,6 @@ const DropdownButton = styled(Button)({
});
class DevicesButton extends Component<Props> {
static contextTypes = {
store: PropTypes.object.isRequired,
};
launchEmulator = (name: string) => {
// On Linux, you must run the emulator from the directory it's in because
// reasons ...
@@ -85,7 +80,7 @@ class DevicesButton extends Component<Props> {
icon = 'desktop';
}
const dropdown = [];
const dropdown: any[] = [];
// Physical devices
const connectedDevices = [
@@ -169,10 +164,13 @@ class DevicesButton extends Component<Props> {
if (dropdown.length > 0) {
dropdown.push({type: 'separator' as 'separator'});
}
return (
<ReactReduxContext.Consumer>
{({store}) => {
dropdown.push({
label: 'Open File...',
click: () => {
showOpenDialog(this.context.store);
showOpenDialog(store);
},
});
return (
@@ -180,6 +178,9 @@ class DevicesButton extends Component<Props> {
{buttonLabel}
</DropdownButton>
);
}}
</ReactReduxContext.Consumer>
);
}
}
export default connect<StateFromProps, DispatchFromProps, OwnProps, State>(

View File

@@ -20,7 +20,7 @@ import {
} from 'flipper';
import {unsetShare} from '../reducers/application';
import React, {Component} from 'react';
import PropTypes from 'prop-types';
import {ReactReduxContext} from 'react-redux';
export type SelectionType = 'multiple' | 'single';
@@ -122,10 +122,6 @@ class RowComponent extends Component<RowComponentProps> {
}
export default class ListView extends Component<Props, State> {
static contextTypes = {
store: PropTypes.object.isRequired,
};
state: State = {selectedElements: new Set([])};
static getDerivedStateFromProps(props: Props, state: State) {
if (state.selectedElements.size > 0) {
@@ -161,11 +157,13 @@ export default class ListView extends Component<Props, State> {
};
render() {
return (
<ReactReduxContext.Consumer>
{({store}) => {
const onHide = () => {
this.context.store.dispatch(unsetShare());
store.dispatch(unsetShare());
this.props.onHide();
};
return (
<Container>
<FlexColumn>
@@ -202,5 +200,8 @@ export default class ListView extends Component<Props, State> {
</Padder>
</Container>
);
}}
</ReactReduxContext.Consumer>
);
}
}

View File

@@ -19,9 +19,10 @@ import {
exportStoreToFile,
EXPORT_FLIPPER_TRACE_EVENT,
} from '../utils/exportData';
import PropTypes from 'prop-types';
import ShareSheetErrorList from './ShareSheetErrorList';
import ShareSheetPendingDialog from './ShareSheetPendingDialog';
import {ReactReduxContext} from 'react-redux';
import {store} from '../init';
const Container = styled(FlexColumn)({
padding: 20,
@@ -75,10 +76,6 @@ type State = {
};
export default class ShareSheetExportFile extends Component<Props, State> {
static contextTypes = {
store: PropTypes.object.isRequired,
};
state: State = {
errorArray: [],
result: {kind: 'pending'},
@@ -89,13 +86,13 @@ export default class ShareSheetExportFile extends Component<Props, State> {
idler = new Idler();
dispatchAndUpdateToolBarStatus(msg: string) {
this.context.store.dispatch(
store.dispatch(
setExportStatusComponent(
<CancellableExportStatus
msg={msg}
onCancel={() => {
this.idler.cancel();
this.context.store.dispatch(unsetShare());
store.dispatch(unsetShare());
}}
/>,
),
@@ -110,21 +107,16 @@ export default class ShareSheetExportFile extends Component<Props, State> {
return;
}
const {errorArray} = await reportPlatformFailures(
exportStoreToFile(
this.props.file,
this.context.store,
this.idler,
(msg: string) => {
exportStoreToFile(this.props.file, store, this.idler, (msg: string) => {
if (this.state.runInBackground) {
this.dispatchAndUpdateToolBarStatus(msg);
} else {
this.setState({statusUpdate: msg});
}
},
),
}),
`${EXPORT_FLIPPER_TRACE_EVENT}:UI_FILE`,
);
this.context.store.dispatch(unsetShare());
store.dispatch(unsetShare());
if (this.state.runInBackground) {
new Notification('Sharable Flipper trace created', {
body: `Flipper trace exported to the ${this.props.file}`,
@@ -142,8 +134,10 @@ export default class ShareSheetExportFile extends Component<Props, State> {
}
}
renderSuccess(context: any) {
renderSuccess() {
return (
<ReactReduxContext.Consumer>
{({store}) => (
<Container>
<FlexColumn>
<Title bold>Data Exported Successfully</Title>
@@ -156,16 +150,20 @@ export default class ShareSheetExportFile extends Component<Props, State> {
</FlexColumn>
<FlexRow>
<Spacer />
<Button compact padded onClick={() => this.cancelAndHide(context)}>
<Button compact padded onClick={() => this.cancelAndHide(store)}>
Close
</Button>
</FlexRow>
</Container>
)}
</ReactReduxContext.Consumer>
);
}
renderError(context: any, result: {kind: 'error'; error: Error}) {
renderError(result: {kind: 'error'; error: Error}) {
return (
<ReactReduxContext.Consumer>
{({store}) => (
<Container>
<Title bold>Error</Title>
<ErrorMessage code>
@@ -173,20 +171,24 @@ export default class ShareSheetExportFile extends Component<Props, State> {
</ErrorMessage>
<FlexRow>
<Spacer />
<Button compact padded onClick={() => this.cancelAndHide(context)}>
<Button compact padded onClick={() => this.cancelAndHide(store)}>
Close
</Button>
</FlexRow>
</Container>
)}
</ReactReduxContext.Consumer>
);
}
renderPending(context: any, statusUpdate: string | null) {
renderPending(statusUpdate: string | null) {
return (
<ReactReduxContext.Consumer>
{({store}) => (
<ShareSheetPendingDialog
statusUpdate={statusUpdate}
statusMessage="Exporting Flipper trace..."
onCancel={() => this.cancelAndHide(context)}
onCancel={() => this.cancelAndHide(store)}
onRunInBackground={() => {
this.setState({runInBackground: true});
if (statusUpdate) {
@@ -195,11 +197,13 @@ export default class ShareSheetExportFile extends Component<Props, State> {
this.props.onHide();
}}
/>
)}
</ReactReduxContext.Consumer>
);
}
cancelAndHide(context: any) {
context.store.dispatch(unsetShare());
cancelAndHide(store: any) {
store.dispatch(unsetShare());
this.props.onHide();
this.idler.cancel();
}
@@ -208,11 +212,11 @@ export default class ShareSheetExportFile extends Component<Props, State> {
const {result, statusUpdate} = this.state;
switch (result.kind) {
case 'success':
return this.renderSuccess(this.context);
return this.renderSuccess();
case 'error':
return this.renderError(this.context, result);
return this.renderError(result);
case 'pending':
return this.renderPending(this.context, statusUpdate);
return this.renderPending(statusUpdate);
}
}
}

View File

@@ -17,6 +17,8 @@ import {
Input,
} from 'flipper';
import React, {Component} from 'react';
import {ReactReduxContext} from 'react-redux';
import {store} from '../init';
import {
setExportStatusComponent,
unsetShare,
@@ -30,7 +32,6 @@ import {
DataExportError,
} from '../fb-stubs/user';
import {exportStore, EXPORT_FLIPPER_TRACE_EVENT} from '../utils/exportData';
import PropTypes from 'prop-types';
import {clipboard} from 'electron';
import ShareSheetErrorList from './ShareSheetErrorList';
import {reportPlatformFailures} from '../utils/metrics';
@@ -80,10 +81,6 @@ type State = {
};
export default class ShareSheetExportUrl extends Component<Props, State> {
static contextTypes = {
store: PropTypes.object.isRequired,
};
state: State = {
errorArray: [],
result: null,
@@ -94,13 +91,13 @@ export default class ShareSheetExportUrl extends Component<Props, State> {
idler = new Idler();
dispatchAndUpdateToolBarStatus(msg: string) {
this.context.store.dispatch(
store.dispatch(
setExportStatusComponent(
<CancellableExportStatus
msg={msg}
onCancel={() => {
this.idler.cancel();
this.context.store.dispatch(unsetShare());
store.dispatch(unsetShare());
}}
/>,
),
@@ -119,7 +116,7 @@ export default class ShareSheetExportUrl extends Component<Props, State> {
}
};
const {serializedString, errorArray} = await reportPlatformFailures(
exportStore(this.context.store, this.idler, statusUpdate),
exportStore(store, this.idler, statusUpdate),
`${EXPORT_FLIPPER_TRACE_EVENT}:UI_LINK`,
);
@@ -135,7 +132,7 @@ export default class ShareSheetExportUrl extends Component<Props, State> {
const flipperUrl = (result as DataExportResult).flipperUrl;
if (flipperUrl) {
clipboard.writeText(String(flipperUrl));
this.context.store.dispatch(setExportURL(flipperUrl));
store.dispatch(setExportURL(flipperUrl));
new Notification('Sharable Flipper trace created', {
body: 'URL copied to clipboard',
requireInteraction: true,
@@ -158,7 +155,7 @@ export default class ShareSheetExportUrl extends Component<Props, State> {
}
this.setState({result});
}
this.context.store.dispatch(unsetShare());
store.dispatch(unsetShare());
this.props.logger.trackTimeSince(mark, 'export:url-error');
}
}
@@ -181,12 +178,19 @@ export default class ShareSheetExportUrl extends Component<Props, State> {
}
}
renderPending(cancelAndHide: () => void, statusUpdate: string | null) {
cancelAndHide = (store: any) => () => {
store.dispatch(unsetShare());
this.hideSheet();
};
renderPending(statusUpdate: string | null) {
return (
<ReactReduxContext.Consumer>
{({store}) => (
<ShareSheetPendingDialog
statusUpdate={statusUpdate}
statusMessage="Uploading Flipper trace..."
onCancel={cancelAndHide}
onCancel={this.cancelAndHide(store)}
onRunInBackground={() => {
this.setState({runInBackground: true});
if (statusUpdate) {
@@ -195,21 +199,20 @@ export default class ShareSheetExportUrl extends Component<Props, State> {
this.props.onHide();
}}
/>
)}
</ReactReduxContext.Consumer>
);
}
render() {
const cancelAndHide = () => {
this.context.store.dispatch(unsetShare());
this.hideSheet();
};
const {result, statusUpdate, errorArray} = this.state;
if (!result || !(result as DataExportResult).flipperUrl) {
return this.renderPending(cancelAndHide, statusUpdate);
return this.renderPending(statusUpdate);
}
return (
<ReactReduxContext.Consumer>
{({store}) => (
<Container>
<>
<FlexColumn>
@@ -217,9 +220,9 @@ export default class ShareSheetExportUrl extends Component<Props, State> {
<>
<Title bold>Data Upload Successful</Title>
<InfoText>
Flipper's data was successfully uploaded. This URL can be used
to share with other Flipper users. Opening it will import the
data from your trace.
Flipper's data was successfully uploaded. This URL can be
used to share with other Flipper users. Opening it will
import the data from your trace.
</InfoText>
<Copy value={(result as DataExportResult).flipperUrl} />
<InfoText>
@@ -243,12 +246,14 @@ export default class ShareSheetExportUrl extends Component<Props, State> {
</FlexColumn>
<FlexRow>
<Spacer />
<Button compact padded onClick={cancelAndHide}>
<Button compact padded onClick={this.cancelAndHide(store)}>
Close
</Button>
</FlexRow>
</>
</Container>
)}
</ReactReduxContext.Consumer>
);
}
}

View File

@@ -32,7 +32,7 @@ import {setPersistor} from './utils/persistor';
import React from 'react';
import path from 'path';
const store = createStore<StoreState, Actions, any, any>(
export const store = createStore<StoreState, Actions, any, any>(
reducers,
window.__REDUX_DEVTOOLS_EXTENSION__
? window.__REDUX_DEVTOOLS_EXTENSION__({

View File

@@ -702,7 +702,7 @@
pirates "^4.0.0"
source-map-support "^0.5.9"
"@babel/runtime@^7.0.0", "@babel/runtime@^7.1.2", "@babel/runtime@^7.1.5", "@babel/runtime@^7.4.2", "@babel/runtime@^7.4.5", "@babel/runtime@^7.5.5", "@babel/runtime@^7.6.0", "@babel/runtime@^7.6.2", "@babel/runtime@^7.6.3":
"@babel/runtime@^7.0.0", "@babel/runtime@^7.1.5", "@babel/runtime@^7.4.2", "@babel/runtime@^7.4.5", "@babel/runtime@^7.5.5", "@babel/runtime@^7.6.0", "@babel/runtime@^7.6.2", "@babel/runtime@^7.6.3":
version "7.6.3"
resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.6.3.tgz#935122c74c73d2240cafd32ddb5fc2a6cd35cf1f"
integrity sha512-kq6anf9JGjW8Nt5rYfEuGRaEAaH1mkv3Bbu6rYvLOpPh/RusSJXuKPEAoZ7L7gybZkchE8+NV5g9vKF4AGAtsA==
@@ -1265,7 +1265,7 @@
dependencies:
"@types/react" "*"
"@types/react-redux@^7.1.1":
"@types/react-redux@^7.1.5":
version "7.1.5"
resolved "https://registry.yarnpkg.com/@types/react-redux/-/react-redux-7.1.5.tgz#c7a528d538969250347aa53c52241051cf886bd3"
integrity sha512-ZoNGQMDxh5ENY7PzU7MVonxDzS1l/EWiy8nUhDqxFqUZn4ovboCyvk4Djf68x6COb7vhGTKjyjxHxtFdAA5sUA==
@@ -6685,7 +6685,7 @@ prompts@^2.0.1:
kleur "^3.0.3"
sisteransi "^1.0.3"
prop-types@^15.5.10, prop-types@^15.6.0, prop-types@^15.6.1, prop-types@^15.6.2, prop-types@^15.7.2:
prop-types@^15.5.10, prop-types@^15.6.0, prop-types@^15.6.2, prop-types@^15.7.2:
version "15.7.2"
resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.7.2.tgz#52c41e75b8c87e72b9d9360e0206b99dcbffa6c5"
integrity sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ==
@@ -6830,28 +6830,27 @@ react-emotion@^9.2.6:
babel-plugin-emotion "^9.2.11"
create-emotion-styled "^9.2.8"
react-is@^16.6.0, react-is@^16.7.0, react-is@^16.8.1, react-is@^16.8.4, react-is@^16.8.6:
react-is@^16.7.0, react-is@^16.8.1, react-is@^16.8.4, react-is@^16.8.6:
version "16.10.2"
resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.10.2.tgz#984120fd4d16800e9a738208ab1fba422d23b5ab"
integrity sha512-INBT1QEgtcCCgvccr5/86CfD71fw9EPmDxgiJX4I2Ddr6ZsV6iFXsuby+qWJPtmNuMY0zByTsG4468P7nHuNWA==
react-lifecycles-compat@^3.0.0:
version "3.0.4"
resolved "https://registry.yarnpkg.com/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz#4f1a273afdfc8f3488a8c516bfda78f872352362"
integrity sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA==
react-is@^16.9.0:
version "16.11.0"
resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.11.0.tgz#b85dfecd48ad1ce469ff558a882ca8e8313928fa"
integrity sha512-gbBVYR2p8mnriqAwWx9LbuUrShnAuSCNnuPGyc7GJrMVQtPDAh8iLpv7FRuMPFb56KkaVZIYSz1PrjI9q0QPCw==
react-redux@^5.0.7:
version "5.1.2"
resolved "https://registry.yarnpkg.com/react-redux/-/react-redux-5.1.2.tgz#b19cf9e21d694422727bf798e934a916c4080f57"
integrity sha512-Ns1G0XXc8hDyH/OcBHOxNgQx9ayH3SPxBnFCOidGKSle8pKihysQw2rG/PmciUQRoclhVBO8HMhiRmGXnDja9Q==
react-redux@^7.1.1:
version "7.1.1"
resolved "https://registry.yarnpkg.com/react-redux/-/react-redux-7.1.1.tgz#ce6eee1b734a7a76e0788b3309bf78ff6b34fa0a"
integrity sha512-QsW0vcmVVdNQzEkrgzh2W3Ksvr8cqpAv5FhEk7tNEft+5pp7rXxAudTz3VOPawRkLIepItpkEIyLcN/VVXzjTg==
dependencies:
"@babel/runtime" "^7.1.2"
"@babel/runtime" "^7.5.5"
hoist-non-react-statics "^3.3.0"
invariant "^2.2.4"
loose-envify "^1.1.0"
prop-types "^15.6.1"
react-is "^16.6.0"
react-lifecycles-compat "^3.0.0"
loose-envify "^1.4.0"
prop-types "^15.7.2"
react-is "^16.9.0"
react-test-renderer@^16.11.0:
version "16.11.0"