Skip to content

Commit

Permalink
Remove AsyncStorage from rn-tester and fix InternalSettings Example
Browse files Browse the repository at this point in the history
Summary:
Changelog:
[**General**][**Removed**] - Removed AsyncStorage usage from RNTester

As part of the "Lean Core" efforts (see react-native-community/discussions-and-proposals#6) to remove outdated and/or unused components (status: https://gist.github.com/Simek/88a9f1a014a47c37f4fce3738864d2e1), this diff removes usage of the deprecated AsyncStorage API from RNTester.

RNTester is intended as a reference to showcase various components and APIs. The implications of the replacement of AsyncStorage in RNTester with in-memory management of state is a tradeoff of persistance to a lighter weight implementation and user predictable behavior.

1. Removed AsyncStorage from rn-tester
  - removed Navigation and bookmark persisting from reducer
  - moved JS Stalls and tracking to application state with context and reducer
2. Fixed InternalSettings Example bugs

Reviewed By: lunaleaps

Differential Revision: D35435562

fbshipit-source-id: a879787d8683a1c452e5b6b75a9e01f3ceadfe5d
  • Loading branch information
J.T. Yim authored and Saadnajmi committed Jan 14, 2023
1 parent 7571236 commit 544a919
Show file tree
Hide file tree
Showing 11 changed files with 323 additions and 322 deletions.
113 changes: 52 additions & 61 deletions packages/rn-tester/js/RNTesterAppShared.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,29 +23,29 @@ import RNTesterNavBar, {navBarHeight} from './components/RNTesterNavbar';
import RNTesterList from './utils/RNTesterList';
import {
Screens,
initialState,
initialNavState,
getExamplesListWithBookmarksAndRecentlyUsed,
getInitialStateFromAsyncStorage,
} from './utils/testerStateUtils';
import {useAsyncStorageReducer} from './utils/useAsyncStorageReducer';
import {RNTesterReducer, RNTesterActionsType} from './utils/RNTesterReducer';
import {
RNTesterNavReducer,
RNTesterNavActionsType,
} from './utils/RNTesterNavReducer';
import {RNTesterThemeContext, themes} from './components/RNTesterTheme';
import RNTTitleBar from './components/RNTTitleBar';
import {RNTesterEmptyBookmarksState} from './components/RNTesterEmptyBookmarksState';
import {RNTesterJsStallsProvider} from './utils/RNTesterJsStallsContext';

const APP_STATE_KEY = 'RNTesterAppState.v3';

// RNTester App currently uses AsyncStorage from react-native for storing navigation state
// RNTester App currently uses in memory storage for storing navigation state
// and bookmark items.
// TODO: Vendor AsyncStorage or create our own.
// TODO: Identify/implement solution for async device storage.
LogBox.ignoreLogs([/AsyncStorage has been extracted from react-native/]);

const RNTesterApp = (): React.Node => {
const [state, dispatch] = useAsyncStorageReducer(
RNTesterReducer,
initialState,
APP_STATE_KEY,
const [state, dispatch] = React.useReducer<Function, Object>(
RNTesterNavReducer,
initialNavState,
);

const colorScheme = useColorScheme();

const {
Expand All @@ -57,17 +57,6 @@ const RNTesterApp = (): React.Node => {
recentlyUsed,
} = state;

React.useEffect(() => {
getInitialStateFromAsyncStorage(APP_STATE_KEY).then(
initialStateFromStorage => {
dispatch({
type: RNTesterActionsType.INIT_FROM_STORAGE,
data: initialStateFromStorage,
});
},
);
}, [dispatch]);

const examplesList = React.useMemo(
() =>
getExamplesListWithBookmarksAndRecentlyUsed({bookmarks, recentlyUsed}),
Expand All @@ -76,7 +65,7 @@ const RNTesterApp = (): React.Node => {

const handleBackPress = React.useCallback(() => {
if (activeModuleKey != null) {
dispatch({type: RNTesterActionsType.BACK_BUTTON_PRESS});
dispatch({type: RNTesterNavActionsType.BACK_BUTTON_PRESS});
}
}, [dispatch, activeModuleKey]);

Expand All @@ -103,7 +92,7 @@ const RNTesterApp = (): React.Node => {
const handleModuleCardPress = React.useCallback(
({exampleType, key, title}) => {
dispatch({
type: RNTesterActionsType.MODULE_CARD_PRESS,
type: RNTesterNavActionsType.MODULE_CARD_PRESS,
data: {exampleType, key, title},
});
},
Expand All @@ -113,7 +102,7 @@ const RNTesterApp = (): React.Node => {
const handleModuleExampleCardPress = React.useCallback(
exampleName => {
dispatch({
type: RNTesterActionsType.EXAMPLE_CARD_PRESS,
type: RNTesterNavActionsType.EXAMPLE_CARD_PRESS,
data: {key: exampleName},
});
},
Expand All @@ -123,7 +112,7 @@ const RNTesterApp = (): React.Node => {
const toggleBookmark = React.useCallback(
({exampleType, key}) => {
dispatch({
type: RNTesterActionsType.BOOKMARK_PRESS,
type: RNTesterNavActionsType.BOOKMARK_PRESS,
data: {exampleType, key},
});
},
Expand All @@ -133,7 +122,7 @@ const RNTesterApp = (): React.Node => {
const handleNavBarPress = React.useCallback(
args => {
dispatch({
type: RNTesterActionsType.NAVBAR_PRESS,
type: RNTesterNavActionsType.NAVBAR_PRESS,
data: {screen: args.screen},
});
},
Expand Down Expand Up @@ -170,40 +159,42 @@ const RNTesterApp = (): React.Node => {

return (
<RNTesterThemeContext.Provider value={theme}>
<RNTTitleBar
title={title}
theme={theme}
onBack={activeModule ? handleBackPress : null}
documentationURL={activeModule?.documentationURL}
/>
<View
style={StyleSheet.compose(styles.container, {
backgroundColor: theme.GroupedBackgroundColor,
})}>
{activeModule != null ? (
<RNTesterModuleContainer
module={activeModule}
example={activeModuleExample}
onExampleCardPress={handleModuleExampleCardPress}
/>
) : screen === Screens.BOOKMARKS &&
examplesList.bookmarks.length === 0 ? (
<RNTesterEmptyBookmarksState />
) : (
<RNTesterModuleList
sections={activeExampleList}
toggleBookmark={toggleBookmark}
handleModuleCardPress={handleModuleCardPress}
/>
)}
</View>
<View style={styles.bottomNavbar}>
<RNTesterNavBar
screen={screen || Screens.COMPONENTS}
isExamplePageOpen={!!activeModule}
handleNavBarPress={handleNavBarPress}
<RNTesterJsStallsProvider>
<RNTTitleBar
title={title}
theme={theme}
onBack={activeModule ? handleBackPress : null}
documentationURL={activeModule?.documentationURL}
/>
</View>
<View
style={StyleSheet.compose(styles.container, {
backgroundColor: theme.GroupedBackgroundColor,
})}>
{activeModule != null ? (
<RNTesterModuleContainer
module={activeModule}
example={activeModuleExample}
onExampleCardPress={handleModuleExampleCardPress}
/>
) : screen === Screens.BOOKMARKS &&
examplesList.bookmarks.length === 0 ? (
<RNTesterEmptyBookmarksState />
) : (
<RNTesterModuleList
sections={activeExampleList}
toggleBookmark={toggleBookmark}
handleModuleCardPress={handleModuleCardPress}
/>
)}
</View>
<View style={styles.bottomNavbar}>
<RNTesterNavBar
screen={screen || Screens.COMPONENTS}
isExamplePageOpen={!!activeModule}
handleNavBarPress={handleNavBarPress}
/>
</View>
</RNTesterJsStallsProvider>
</RNTesterThemeContext.Provider>
);
};
Expand Down
59 changes: 19 additions & 40 deletions packages/rn-tester/js/components/RNTesterSettingSwitchRow.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,54 +8,33 @@
* @flow strict-local
*/

'use strict';

const RNTesterStatePersister = require('../utils/RNTesterStatePersister');
const React = require('react');

const {StyleSheet, Switch, Text, View} = require('react-native');

class RNTesterSettingSwitchRow extends React.Component<
$FlowFixMeProps,
$FlowFixMeState,
> {
UNSAFE_componentWillReceiveProps(newProps: $FlowFixMeProps) {
const {onEnable, onDisable, persister} = this.props;
if (newProps.persister.state !== persister.state) {
newProps.persister.state ? onEnable() : onDisable();
}
}
render(): React.Node {
const {label, persister} = this.props;
return (
<View style={styles.row}>
<Text>{label}</Text>
<Switch
value={persister.state}
onValueChange={value => {
persister.setState(() => value);
}}
/>
</View>
);
}
}
const styles = StyleSheet.create({
row: {
padding: 10,
flexDirection: 'row',
justifyContent: 'space-between',
},
});
/* $FlowFixMe[cannot-reassign-export] (>=0.85.0 site=react_native_fb) This
* comment suppresses an error found when Flow v0.85 was deployed. To see the
* error, delete this comment and run Flow. */
// $FlowFixMe[cannot-reassign]
RNTesterSettingSwitchRow = RNTesterStatePersister.createContainer(
RNTesterSettingSwitchRow,
{
cacheKeySuffix: ({label}) => 'Switch:' + label,
getInitialState: ({initialValue}) => initialValue,
},
);
module.exports = RNTesterSettingSwitchRow;

export const RNTesterSettingSwitchRow = ({
label,
onEnable,
onDisable,
active,
}: $FlowFixMeProps): React.Node => {
return (
<View style={styles.row}>
<Text>{label}</Text>
<Switch
value={active}
onValueChange={() => {
active ? onDisable() : onEnable();
}}
/>
</View>
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -158,74 +158,45 @@ class LoopExample extends React.Component<{...}, $FlowFixMeState> {
}
}

const RNTesterSettingSwitchRow = require('../../components/RNTesterSettingSwitchRow');
class InternalSettings extends React.Component<
{...},
{
busyTime: number | string,
filteredStall: number,
...
},
> {
_stallInterval: ?number;
render() {
return (
<View>
<RNTesterSettingSwitchRow
initialValue={false}
label="Force JS Stalls"
onEnable={() => {
/* $FlowFixMe[incompatible-type] (>=0.63.0 site=react_native_fb)
* This comment suppresses an error found when Flow v0.63 was
* deployed. To see the error delete this comment and run Flow. */
this._stallInterval = setInterval(() => {
const start = Date.now();
console.warn('burn CPU');
while (Date.now() - start < 100) {}
}, 300);
}}
onDisable={() => {
/* $FlowFixMe[incompatible-call] (>=0.63.0 site=react_native_fb)
* This comment suppresses an error found when Flow v0.63 was
* deployed. To see the error delete this comment and run Flow. */
clearInterval(this._stallInterval || 0);
}}
/>
<RNTesterSettingSwitchRow
initialValue={false}
label="Track JS Stalls"
onEnable={() => {
require('react-native/Libraries/Interaction/JSEventLoopWatchdog').install(
{
thresholdMS: 25,
},
);
this.setState({busyTime: '<none>'});
require('react-native/Libraries/Interaction/JSEventLoopWatchdog').addHandler(
{
onStall: ({busyTime}) =>
this.setState(state => ({
busyTime,
filteredStall:
(state.filteredStall || 0) * 0.97 + busyTime * 0.03,
})),
},
);
}}
onDisable={() => {
console.warn('Cannot disable yet....');
}}
/>
{this.state && (
<Text>
{`JS Stall filtered: ${Math.round(this.state.filteredStall)}, `}
{`last: ${this.state.busyTime}`}
</Text>
)}
</View>
);
}
}
const RNTesterSettingSwitchRow =
require('../../components/RNTesterSettingSwitchRow').RNTesterSettingSwitchRow;
const RNTesterJsStallsContext = require('../../utils/RNTesterJsStallsContext');

const InternalSettings = () => {
const {
state,
onDisableForceJsStalls,
onEnableForceJsStalls,
onEnableJsStallsTracking,
onDisableJsStallsTracking,
} = React.useContext(RNTesterJsStallsContext.RNTesterJsStallsContext);

const {stallInterval, busyTime, filteredStall, tracking} = state;
return (
<View>
<RNTesterSettingSwitchRow
initialValue={false}
label="Force JS Stalls"
active={stallInterval !== null}
onEnable={onEnableForceJsStalls}
onDisable={onDisableForceJsStalls}
/>
<RNTesterSettingSwitchRow
initialValue={false}
label="Track JS Stalls"
active={tracking}
onEnable={onEnableJsStallsTracking}
onDisable={onDisableJsStallsTracking}
/>
{tracking && (
<Text>
{`JS Stall filtered: ${Math.round(filteredStall)}, `}
{`last: ${busyTime !== null ? busyTime.toFixed(8) : '<none>'}`}
</Text>
)}
</View>
);
};

class EventExample extends React.Component<{...}, $FlowFixMeState> {
state = {
Expand Down
9 changes: 8 additions & 1 deletion packages/rn-tester/js/types/RNTesterTypes.js
Original file line number Diff line number Diff line change
Expand Up @@ -68,11 +68,18 @@ export type ScreenTypes = 'components' | 'apis' | 'bookmarks' | null;

export type ComponentList = null | {components: string[], apis: string[]};

export type RNTesterState = {
export type RNTesterNavState = {
activeModuleKey: null | string,
activeModuleTitle: null | string,
activeModuleExampleKey: null | string,
screen: ScreenTypes,
bookmarks: ComponentList,
recentlyUsed: ComponentList,
};

export type RNTesterJsStallsState = {
stallInterval: null | number,
busyTime: null | number,
filteredStall: number,
tracking: boolean,
};
Loading

0 comments on commit 544a919

Please sign in to comment.