mirror of
https://gitlab.com/wheres-the-tp/ui-mobile.git
synced 2026-01-25 07:24:56 -06:00
routing and drawer performance fixes
This commit is contained in:
parent
8ce9d4e045
commit
f3d383fb89
4 changed files with 95 additions and 74 deletions
59
js/App.js
59
js/App.js
|
|
@ -7,7 +7,7 @@ import DrawerMenu from './pages/DrawerMenu';
|
|||
import rxjsconfig from 'recompose/rxjsObservableConfig';
|
||||
import setObservableConfig from 'recompose/setObservableConfig';
|
||||
import TopToolbar from './components/TopToolbar';
|
||||
import { NativeRouter, Route, Redirect } from 'react-router-native';
|
||||
import { NativeRouter, Route, Redirect, AndroidBackButton } from 'react-router-native';
|
||||
import List from './pages/List';
|
||||
import FoodItemDetail from './pages/FoodItemDetail';
|
||||
import PlaceDetail from './pages/PlaceDetail';
|
||||
|
|
@ -16,53 +16,42 @@ import CreateFoodItem from './pages/CreateFoodItem';
|
|||
|
||||
setObservableConfig(rxjsconfig);
|
||||
|
||||
type State = {
|
||||
drawerOpen: boolean,
|
||||
};
|
||||
|
||||
export default class App extends Component {
|
||||
state = { drawerOpen: false };
|
||||
|
||||
state: State;
|
||||
static displayName = 'App';
|
||||
|
||||
_drawer: Drawer;
|
||||
|
||||
toggleDrawer = () => {
|
||||
this.setState(({ drawerOpen }) => ({ drawerOpen: !drawerOpen }));
|
||||
};
|
||||
|
||||
closeDrawer = () => {
|
||||
this.setState({ drawerOpen: false });
|
||||
this._drawer.close();
|
||||
};
|
||||
|
||||
openDrawer = () => {
|
||||
this.setState({ drawerOpen: true });
|
||||
this._drawer.open();
|
||||
};
|
||||
|
||||
render() {
|
||||
const { drawerOpen } = this.state;
|
||||
return (
|
||||
<NativeRouter>
|
||||
<ThemeProvider uiTheme={theme}>
|
||||
<Drawer
|
||||
ref={ref => (this._drawer = ref)}
|
||||
type="overlay"
|
||||
open={drawerOpen}
|
||||
onOpen={this.openDrawer}
|
||||
onClose={this.closeDrawer}
|
||||
openDrawerOffset={100}
|
||||
content={<DrawerMenu onCloseDrawer={this.closeDrawer} />}
|
||||
>
|
||||
<View style={theme.page.container}>
|
||||
<TopToolbar toggleSideMenu={this.toggleDrawer} />
|
||||
<Redirect from="/" to="/list/food" />
|
||||
<Route path="/list/:type" component={List} />
|
||||
<Route path="/foodItem/:id" component={FoodItemDetail} />
|
||||
<Route path="/place/:id" component={PlaceDetail} />
|
||||
<Route path="/createFoodItem" component={CreateFoodItem} />
|
||||
</View>
|
||||
</Drawer>
|
||||
</ThemeProvider>
|
||||
<AndroidBackButton>
|
||||
<ThemeProvider uiTheme={theme}>
|
||||
<Drawer
|
||||
ref={ref => (this._drawer = ref)}
|
||||
type="overlay"
|
||||
openDrawerOffset={100}
|
||||
content={<DrawerMenu onCloseDrawer={this.closeDrawer} />}
|
||||
tweenDuration={150}
|
||||
>
|
||||
<View style={theme.page.container}>
|
||||
<TopToolbar toggleSideMenu={this.openDrawer} />
|
||||
<Redirect from="/" to="/list/food" />
|
||||
<Route path="/list/:type" component={List} />
|
||||
<Route path="/foodItem/:id" component={FoodItemDetail} />
|
||||
<Route path="/place/:id" component={PlaceDetail} />
|
||||
<Route path="/createFoodItem" component={CreateFoodItem} />
|
||||
</View>
|
||||
</Drawer>
|
||||
</ThemeProvider>
|
||||
</AndroidBackButton>
|
||||
</NativeRouter>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -23,7 +23,6 @@ class TopToolbar extends Component {
|
|||
const { router: { route, history } } = this.context;
|
||||
|
||||
history.replace({
|
||||
...route.location,
|
||||
state: {
|
||||
...route.location.state,
|
||||
viewMode: action,
|
||||
|
|
@ -37,28 +36,52 @@ class TopToolbar extends Component {
|
|||
|
||||
onSearchChanged: () => {};
|
||||
|
||||
getRightElement = () => {
|
||||
const pathname = path(['router', 'route', 'location', 'pathname'], this.context);
|
||||
const viewMode = path(['router', 'route', 'location', 'state', 'viewMode'], this.context);
|
||||
|
||||
switch (pathname.match(/^\/\w*/)[0]) {
|
||||
case '/list': {
|
||||
return viewMode === 'map' ? 'list' : 'map';
|
||||
}
|
||||
default: {
|
||||
return '';
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
getSearchable = () => {
|
||||
const pathname = path(['router', 'route', 'location', 'pathname'], this.context);
|
||||
|
||||
if (!/list/.test(pathname)) {
|
||||
return {};
|
||||
}
|
||||
|
||||
return {
|
||||
searchable: {
|
||||
autoFocus: true,
|
||||
onSearchPressed: this.onSearchPressed,
|
||||
onSearchClosed: this.onSearchClosed,
|
||||
onChangeText: this.onSearchChanged,
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
render() {
|
||||
const { toggleSideMenu } = this.props;
|
||||
const history = path(['router', 'history'], this.context);
|
||||
const state = path(['router', 'route', 'location', 'state'], this.context) || {};
|
||||
const { routeTitle, viewMode } = state;
|
||||
const routeTitle = path(['router', 'route', 'location', 'state', 'routeTitle'], this.context);
|
||||
const title = routeTitle || this.props.title;
|
||||
const isBasePage = history.index === 0;
|
||||
const modeSwitchIcon = viewMode === 'map' ? 'list' : 'map';
|
||||
|
||||
return (
|
||||
<Toolbar
|
||||
leftElement={isBasePage ? 'menu' : 'arrow-back'}
|
||||
onLeftElementPress={isBasePage ? toggleSideMenu : history.goBack}
|
||||
centerElement={title}
|
||||
rightElement={modeSwitchIcon}
|
||||
rightElement={this.getRightElement()}
|
||||
onRightElementPress={this.onRightPress}
|
||||
searchable={{
|
||||
autoFocus: true,
|
||||
onSearchPressed: this.onSearchPressed,
|
||||
onSearchClosed: this.onSearchClosed,
|
||||
onChangeText: this.onSearchChanged,
|
||||
}}
|
||||
{...this.getSearchable()}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,53 +8,57 @@ import { type RoutingContextFlowTypes, routingContextPropTypes } from '../routes
|
|||
|
||||
const tabs = ['food', 'places'];
|
||||
|
||||
const getTabIndex = (tabName: string) => tabs.indexOf(tabName);
|
||||
|
||||
const getTabName = (index: number) => tabs[index];
|
||||
const getTabIndex = ({ match: { params: { type = '' } } }: RoutingContextFlowTypes): number => {
|
||||
return tabs.indexOf(type) || 0;
|
||||
};
|
||||
|
||||
type TabView = {
|
||||
goToPage: (page: number) => void,
|
||||
};
|
||||
|
||||
type Props = {
|
||||
match: {
|
||||
params: {
|
||||
type?: string,
|
||||
},
|
||||
state: {
|
||||
currentPage: number,
|
||||
},
|
||||
};
|
||||
|
||||
class List extends Component {
|
||||
static contextTypes = routingContextPropTypes;
|
||||
|
||||
props: Props;
|
||||
props: RoutingContextFlowTypes;
|
||||
|
||||
context: RoutingContextFlowTypes;
|
||||
|
||||
tabView: TabView;
|
||||
|
||||
// TODO: find a more routing friendly tab component (or build one)
|
||||
// sync route changes into tab state (yuck)
|
||||
componentWillReceiveProps(newProps: Props) {
|
||||
const { match: { params: { type: newType } } } = newProps;
|
||||
const { match: { params: { type } } } = this.props;
|
||||
if (!!this.tabView && !!newType && type !== newType) {
|
||||
const page = getTabIndex(newType);
|
||||
this.tabView.goToPage(page);
|
||||
updateTabRoute = ({ i }: { i: number }) => {
|
||||
const currentTab = getTabIndex(this.props);
|
||||
|
||||
if (currentTab !== i) {
|
||||
/*
|
||||
routing is slow in react-native so this setTimeout allows for the stateful
|
||||
TabView component to re-render itself before we make a route change
|
||||
(which we expect will then re-render with no tab change)
|
||||
*/
|
||||
setTimeout(() => {
|
||||
this.context.router.history.replace(`/list/${tabs[i]}`);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
componentWillReceiveProps(nextProps: RoutingContextFlowTypes) {
|
||||
if (!this.tabView) {
|
||||
return;
|
||||
}
|
||||
|
||||
const currentTab = getTabIndex(this.props);
|
||||
const nextTab = getTabIndex(nextProps);
|
||||
|
||||
if (currentTab !== nextTab) {
|
||||
this.tabView.goToPage(nextTab);
|
||||
}
|
||||
}
|
||||
|
||||
// sync tab state into route state (yuck)
|
||||
updateTabRoute = ({ i }: { i: number }) => {
|
||||
const type = getTabName(i);
|
||||
this.context.router.history.replace(`/list/${type}`);
|
||||
};
|
||||
|
||||
setTabViewRef = (tabView: TabView) => (this.tabView = tabView);
|
||||
|
||||
render() {
|
||||
const { match: { params: { type = '' } } } = this.props;
|
||||
const page = getTabIndex(type);
|
||||
return (
|
||||
<ScrollableTabView
|
||||
ref={this.setTabViewRef}
|
||||
|
|
@ -64,7 +68,7 @@ class List extends Component {
|
|||
tabBarInactiveTextColor={theme.topTabs.selectedTextColor}
|
||||
prerenderingSiblingsNumber={Infinity}
|
||||
onChangeTab={this.updateTabRoute}
|
||||
initialPage={page}
|
||||
initialPage={getTabIndex(this.props)}
|
||||
>
|
||||
<Food tabLabel="FOOD" />
|
||||
<Places tabLabel="PLACES" />
|
||||
|
|
|
|||
|
|
@ -77,4 +77,9 @@ export type RoutingContextFlowTypes = {
|
|||
},
|
||||
},
|
||||
},
|
||||
match: {
|
||||
params: {
|
||||
type?: string,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue