Last active
November 17, 2016 15:42
-
-
Save kristojorg/2a3ece819acd008276b4fba760234e26 to your computer and use it in GitHub Desktop.
Example of a SceneWrapper component, which returns false from shouldComponentUpdate when screen is not in view, and provides a new lifecycle hook for when screen is newly in view.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import React, { PropTypes } from 'react'; | |
import { connect } from 'react-redux'; | |
import scAx from '../utils/tracking'; | |
import { selectors } from '../redux/index'; | |
const SceneWrapper = ComposedComponent => class Wrapper extends React.Component { | |
static propTypes = { | |
refresh: PropTypes.func, | |
scene: PropTypes.string, | |
sceneName: PropTypes.string, | |
drawerIsOpen: PropTypes.bool, | |
appState: PropTypes.bool, | |
globals: PropTypes.object, | |
myId: PropTypes.number, | |
gu: PropTypes.string, | |
guid: PropTypes.number, | |
myName: PropTypes.string, | |
} | |
static defaultProps = { | |
refresh: null, | |
scene: null, | |
sceneName: null, | |
drawerIsOpen: false, | |
appState: true, | |
globals: null, | |
myId: null, | |
gu: null, | |
guid: null, | |
} | |
constructor(props) { | |
super(props); | |
this.state = { | |
isNewlyInFocus: false, | |
isRefreshing: false, | |
hasFetchedOnce: false, | |
}; | |
this.lastGu = props.lastGu; | |
this.lastGuid = props.lastGuid; | |
} | |
componentWillReceiveProps(nextProps) { | |
if (this.isNewlyInFocus(this.props, nextProps)) { | |
// console.log('This scene is newly in focus. Let it know', this.props.sceneName); | |
this.setState({ | |
isNewlyInFocus: true, | |
}); | |
} else { | |
// console.log('This scene is NOT newly in focus. Let it know', this.props.sceneName); | |
this.setState({ | |
isNewlyInFocus: false, | |
}); | |
} | |
} | |
componentDidMount() { | |
// if (this.props.refresh) this.props.refresh(); | |
this.refresh(); | |
this.identifyUser(); | |
} | |
shouldComponentUpdate(nextP) { | |
const { props } = this; | |
if (!this.isInFocus(nextP.scene, nextP.drawerIsOpen)) { | |
return false; | |
} | |
return true; | |
} | |
componentDidUpdate(prevProps) { | |
// if (this.isNewlyInFocus(prevProps, this.props)) { | |
if (this.state.isNewlyInFocus) { | |
// refresh the content if this is newly in focus... | |
this.refresh(); | |
} | |
if (!prevProps.appState && this.props.appState) { | |
// identify the user if the app state is newly in the foreground. | |
this.identifyUser(); | |
} | |
this.lastGu = this.props.gu; | |
this.lastGuid = this.props.guid; | |
// console.log('COMPONENT DID UPDATE', this.props.gu, this.props.guid, this.isNewlyInFocus(prevProps, this.props)); | |
} | |
identifyUser = () => { | |
const codePushVer = this.props.globals.getIn(['codePushVer']); | |
const codePushDescription = this.props.globals.get('codePushDescription', 'n/a'); | |
const codePushIsPending = String(this.props.globals.get('codePushIsPending', 'n/a')); | |
const appVersion = this.props.globals.get('appVersion', 'n/a'); | |
const syncStatus = this.props.globals.get('syncStatus', 'none'); | |
const traits = { | |
codePushVer, | |
codePushIsPending, | |
codePushDescription, | |
appVersion, | |
syncStatus, | |
}; | |
if (this.props.myName) { | |
traits.name = this.props.myName; | |
} | |
scAx.identify(this.props.myId, traits); | |
} | |
refresh = () => { | |
if (this.props.refresh) { | |
const r = this.props.refresh(); | |
if (r && r.then) { | |
this.setState({ | |
isRefreshing: true, | |
isNewlyInFocus: false, | |
}); | |
return r.catch(e => { | |
console.warn('Error refreshing in ', this.props.sceneName, e); | |
this.setState({ | |
isRefreshing: false, | |
hasFetchedOnce: true, | |
isNewlyInFocus: false, | |
}); | |
}).then(result => { | |
this.setState({ | |
isRefreshing: false, | |
hasFetchedOnce: true, | |
isNewlyInFocus: false, | |
}); | |
}); | |
} | |
// this.props.refresh(); | |
return Promise.resolve('Refresh was not a promise in SceneWrapper.'); | |
} | |
return Promise.resolve('No refresh function provided to SceneWrapper.'); | |
} | |
isInFocus = (scene, drawerIsOpen) => { | |
if ( | |
scene === this.props.sceneName && | |
!drawerIsOpen | |
) return true; | |
return false; | |
} | |
justClosedDrawer = (prevDrawer, nextDrawer) => { | |
if (prevDrawer && !nextDrawer) return true; | |
return false; | |
} | |
isNewlyInFocus = (prevProps, nextProps) => { | |
// did you just close the drawer and the current scene is in focus? Get new data. | |
// did you just switch from another tab and the current scene is in focus? get new data. | |
const { scene: prevScene, appState: prevAppState } = prevProps; | |
const { scene: nextScene, guid: nextGuid, gu: nextGu, appState: nextAppState } = nextProps; | |
const lastGu = this.lastGu; | |
const lastGuid = this.lastGuid; | |
// did you just switch from another tab? | |
if ( | |
// it didn't used to be in focus! | |
!this.isInFocus(prevScene) && | |
// but now it is in focus | |
this.isInFocus(nextScene) | |
) return true; | |
/* A couple other conditions to check, given the scene is in focus at all: | |
1. If you switched from another account | |
2. If you just came from background app state. | |
first check that the scene is in focus at all... | |
*/ | |
if (this.isInFocus(nextScene)) { | |
// then check if you have changed gu or guid | |
if ( | |
lastGu !== nextGu || | |
lastGuid !== nextGuid | |
) { | |
this.setState({ | |
hasFetchedOnce: false, | |
}); | |
return true; | |
} | |
if ( | |
// the app did not used to be in foreground | |
!prevAppState && | |
// it is now in foreground | |
nextAppState | |
) return true; | |
} | |
return false; | |
} | |
render() { | |
return ( | |
<ComposedComponent | |
{...this.props} | |
isNewlyInFocus={this.state.isNewlyInFocus} | |
isRefreshing={this.state.isRefreshing} | |
refresh={this.refresh} | |
hasFetchedOnce={this.state.hasFetchedOnce} | |
/> | |
); | |
} | |
}; | |
function mapStateToProps(state: any) { | |
return { | |
scene: selectors.getScene(state), | |
drawerIsOpen: selectors.getDrawerIsOpen(state), | |
appState: selectors.getAppState(state), | |
globals: selectors.getGlobals(state), | |
myId: selectors.getMyId(state), | |
gu: selectors.getGu(state), | |
guid: selectors.getGuid(state), | |
myName: selectors.getMyName(state), | |
}; | |
} | |
const SceneWrapperConnected = ComposedComponent => connect(mapStateToProps)(SceneWrapper(ComposedComponent)); | |
export default SceneWrapperConnected; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment