Skip to content

Commit

Permalink
Suspend connected components when not active route
Browse files Browse the repository at this point in the history
  • Loading branch information
chromakode committed Jul 18, 2017
1 parent 52075ea commit c97d248
Show file tree
Hide file tree
Showing 10 changed files with 69 additions and 31 deletions.
4 changes: 2 additions & 2 deletions shared/app/nav.desktop.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,8 @@ function Nav(props: Props) {
badgeNumbers={props.navBadges.toJS()}
/>}
<Box style={{...globalStyles.flexBoxColumn, flex: 1}}>
{visibleScreen.component}
{layerScreens.map(r => r.leafComponent)}
{visibleScreen.component({isActive: true})}
{layerScreens.map(r => r.leafComponent({isActive: true}))}
</Box>
<div id="popupContainer" />
{![chatTab, loginTab].includes(props.routeSelected) &&
Expand Down
23 changes: 13 additions & 10 deletions shared/app/nav.native.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ type OwnProps = RouteProps<{}, {}>

type CardStackShimProps = {
mode?: 'modal',
renderRoute: (route: RenderRouteResult) => React$Element<*>,
renderRoute: (route: RenderRouteResult, isActive: boolean) => React$Element<*>,
onNavigateBack: () => void,
stack: RouteRenderStack,
hidden?: boolean,
Expand All @@ -41,8 +41,8 @@ class CardStackShim extends Component<*, CardStackShimProps, *> {
getComponentForRouteName = () => this.RenderRouteShim

RenderRouteShim = ({navigation}) => {
const route = navigation.state.params
return this.props.renderRoute(route)
const {route, isActive} = navigation.state.params
return this.props.renderRoute(route, isActive)
}

_dispatchShim = (action: NavigationAction) => {
Expand All @@ -67,9 +67,12 @@ class CardStackShim extends Component<*, CardStackShimProps, *> {
state: {
index: stack.size - 1,
routes: stack
.map(route => {
.map((route, index) => {
const routeName = route.path.join('/')
return {key: routeName, routeName, params: route}
// Immutable.Stack indexes go from N-1(top/front)...0(bottom/back)
// The bottom/back item of the stack is our top (active) screen
const isActive = !this.props.hidden && index === 0
return {key: routeName, routeName, params: {route, isActive}}
})
.toArray(),
},
Expand Down Expand Up @@ -114,11 +117,11 @@ const barStyle = ({showStatusBarDarkContent, underStatusBar}) => {
return 'dark-content'
}

function renderStackRoute(route) {
function renderStackRoute(route, isActive) {
const {underStatusBar, hideStatusBar, showStatusBarDarkContent} = route.tags
// Skip extra view if no statusbar
if (hideStatusBar) {
return route.component
return route.component({isActive})
}

return (
Expand All @@ -129,7 +132,7 @@ function renderStackRoute(route) {
backgroundColor="rgba(0, 26, 51, 0.25)"
barStyle={barStyle({showStatusBarDarkContent, underStatusBar})}
/>
{route.component}
{route.component({isActive})}
</Box>
)
}
Expand Down Expand Up @@ -222,7 +225,7 @@ function Nav(props: Props) {
const mainScreens = baseScreens.takeUntil(fullscreenPred)
const fullScreens = baseScreens.skipUntil(fullscreenPred).unshift({
path: ['main'],
component: <MainNavStack {...props} routeStack={mainScreens} />,
component: () => <MainNavStack {...props} routeStack={mainScreens} />,
tags: {underStatusBar: true}, // don't pad nav stack (child screens have own padding)
})

Expand All @@ -235,7 +238,7 @@ function Nav(props: Props) {
/>
)
const layerScreens = props.routeStack.filter(r => r.tags.layerOnTop)
const layers = layerScreens.map(r => r.leafComponent)
const layers = layerScreens.map(r => r.leafComponent({isActive: true}))

// If we have layers, lets add an extra box, else lets just pass through
if (layers.count()) {
Expand Down
4 changes: 2 additions & 2 deletions shared/chat/conversation/container.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import * as Creators from '../../actions/chat/creators'
import Conversation from './index'
import NoConversation from './no-conversation'
import Rekey from './rekey/container'
import {connect} from 'react-redux'
import pausableConnect from '../../util/pausable-connect'
import {getProfile} from '../../actions/tracker'
import {withState, withHandlers, compose, branch, renderNothing, renderComponent} from 'recompose'
import {selectedSearchIdHoc} from '../../searchv3/helpers'
Expand Down Expand Up @@ -117,7 +117,7 @@ const mergeProps = (stateProps: StateProps, dispatchProps: DispatchProps) => {
}

export default compose(
connect(mapStateToProps, mapDispatchToProps, mergeProps),
pausableConnect(mapStateToProps, mapDispatchToProps, mergeProps),
branch((props: Props) => !props.selectedConversationIDKey, renderNothing),
branch(
(props: Props) => props.selectedConversationIDKey === Constants.nothingSelected && !props.inSearch,
Expand Down
4 changes: 2 additions & 2 deletions shared/chat/inbox/container.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
import * as I from 'immutable'
import * as Constants from '../../constants/chat'
import Inbox from './index'
import {connect} from 'react-redux'
import pausableConnect from '../../util/pausable-connect'
import {createSelectorCreator, defaultMemoize} from 'reselect'
import {loadInbox, newChat, untrustedInboxVisible} from '../../actions/chat/creators'
import {compose, lifecycle} from 'recompose'
Expand Down Expand Up @@ -61,7 +61,7 @@ const mapDispatchToProps = (dispatch: Dispatch) => ({
const throttleHelper = throttle(cb => cb(), 60 * 1000)

export default compose(
connect(mapStateToProps, mapDispatchToProps),
pausableConnect(mapStateToProps, mapDispatchToProps),
lifecycle({
componentDidMount: function() {
throttleHelper(() => {
Expand Down
4 changes: 2 additions & 2 deletions shared/chat/render.desktop.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@ import React from 'react'
import Inbox from './inbox/container'
import {globalStyles} from '../styles'

const Render = ({children}: {children: any}) => (
const Render = ({isActive, children}: {isActive: boolean, children: any}) => (
<div style={style}>
<Inbox />
<Inbox isActive={isActive} />
{children}
</div>
)
Expand Down
4 changes: 2 additions & 2 deletions shared/folders/index.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// @flow
import React, {Component} from 'react'
import Render from './render'
import {connect} from 'react-redux'
import pausableConnect from '../util/pausable-connect'
import {favoriteList} from '../actions/favorite'
import {openInKBFS} from '../actions/kbfs'
import {openTlfInChat} from '../actions/chat'
Expand Down Expand Up @@ -70,7 +70,7 @@ const mapDispatchToProps = (dispatch: any, {routePath, routeState, setRouteState
onToggleShowIgnored: () => setRouteState({showingIgnored: !routeState.showingIgnored}),
})

const ConnectedFolders = connect(mapStateToProps, mapDispatchToProps)(Folders)
const ConnectedFolders = pausableConnect(mapStateToProps, mapDispatchToProps)(Folders)

export function PrivateFolders(props: FoldersRouteProps) {
return <ConnectedFolders showingPrivate={true} {...props} />
Expand Down
4 changes: 2 additions & 2 deletions shared/profile/container.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import {
checkProof,
} from '../actions/profile'
import {searchSuggestions} from '../actions/searchv3/creators'
import {connect} from 'react-redux'
import pausableConnect from '../util/pausable-connect'
import {getProfile, updateTrackers, onFollow, onUnfollow, openProofUrl} from '../actions/tracker'
import {isLoading} from '../constants/tracker'
import {isTesting} from '../local-debug'
Expand Down Expand Up @@ -55,7 +55,7 @@ class ProfileContainer extends PureComponent<void, EitherProps<Props>, void> {
}
}

export default connect(
export default pausableConnect(
(state, {routeProps, routeState, routePath}: OwnProps) => {
const myUsername = state.config.username
const username = routeProps.username ? routeProps.username : myUsername
Expand Down
28 changes: 21 additions & 7 deletions shared/route-tree/render-route.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@ import type {RouteDefNode, RouteStateNode, Path} from './'
type _RenderRouteResultParams = {
path: I.List<string>,
tags: LeafTags,
component: React$Element<any>,
leafComponent: React$Element<any>,
component: ({isActive: boolean}) => React$Element<any>,
leafComponent: ({isActive: boolean}) => React$Element<any>,
}

export const RenderRouteResult: (
Expand Down Expand Up @@ -54,6 +54,7 @@ export type RouteProps<P, S> = {
}

type RenderRouteNodeProps<S> = {
isActive: boolean,
isContainer: boolean,
routeDef: RouteDefNode,
routeState: RouteStateNode,
Expand All @@ -68,10 +69,21 @@ type RenderRouteNodeProps<S> = {
// shouldComponentUpdate (via PureComponent).
class RenderRouteNode extends PureComponent<*, RenderRouteNodeProps<*>, *> {
render() {
const {isContainer, routeDef, routeState, setRouteState, path, leafTags, stack, children} = this.props
const {
isActive,
isContainer,
routeDef,
routeState,
setRouteState,
path,
leafTags,
stack,
children,
} = this.props
const RouteComponent = isContainer ? routeDef.containerComponent : routeDef.component
return (
<RouteComponent
isActive={isActive}
routeProps={routeState.props.toObject()}
routeState={routeDef.initialState.merge(routeState.state).toObject()}
routeSelected={routeState.selected}
Expand Down Expand Up @@ -135,8 +147,9 @@ function renderRouteStack({
// If this route specifies a container component, compose it around every
// view in the stack.
stack = stack.map(r =>
r.update('component', child => (
r.update('component', child => ({isActive}) => (
<RenderRouteNode
isActive={isActive}
isContainer={true}
routeDef={routeDef}
routeState={routeState}
Expand All @@ -145,7 +158,7 @@ function renderRouteStack({
leafTags={childStack.last().tags}
stack={childStack}
>
{child}
{child({isActive})}
</RenderRouteNode>
))
)
Expand All @@ -154,8 +167,9 @@ function renderRouteStack({

if (routeDef.component) {
// If this path has a leaf component to render, add it to the stack.
const routeComponent = (
const routeComponent = ({isActive}) => (
<RenderRouteNode
isActive={isActive}
isContainer={false}
routeDef={routeDef}
routeState={routeState}
Expand Down Expand Up @@ -188,6 +202,6 @@ export default class RenderRoute extends PureComponent<*, RenderRouteProps<*>, *
// renderRouteStack gives us a stack of all views down the current route path.
// This component renders the bottom (currently visible) one.
var viewStack = renderRouteStack({...this.props, path: I.List()})
return viewStack.last().component
return viewStack.last().component({isActive: true})
}
}
4 changes: 2 additions & 2 deletions shared/settings/index.js
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
// @flow
import SettingsContainer from './render'
import {connect} from 'react-redux'
import pausableConnect from '../util/pausable-connect'
import {switchTo} from '../actions/route-tree'
import {logout} from '../actions/login/creators'

import type {RouteProps} from '../route-tree/render-route'

// $FlowIssue type this connector
export default connect(
export default pausableConnect(
(state, {routeSelected, routeLeafTags}: RouteProps<{}, {}>) => ({
badgeNumbers: {}, // TODO add badging logic
selectedTab: routeSelected,
Expand Down
21 changes: 21 additions & 0 deletions shared/util/pausable-connect.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
// @flow
import {createConnect} from 'react-redux/src/connect/connect'
import defaultSelectorFactory from 'react-redux/src/connect/selectorFactory'

import typeof {connect} from 'react-redux'

function selectorFactory(dispatch, factoryOptions) {
const selector = defaultSelectorFactory(dispatch, factoryOptions)
let cachedResult
const pausableSelector = function(state, ownProps) {
if (ownProps.isActive || cachedResult === undefined) {
cachedResult = selector(state, ownProps)
}
return cachedResult
}
return pausableSelector
}

const pausableConnect: connect = createConnect({selectorFactory})

export default pausableConnect

0 comments on commit c97d248

Please sign in to comment.