Skip to content

Instantly share code, notes, and snippets.

@kristojorg
Last active November 17, 2016 15:42
Show Gist options
  • Save kristojorg/2a3ece819acd008276b4fba760234e26 to your computer and use it in GitHub Desktop.
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.
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