Search code examples
react-nativereact-native-router-fluxreact-native-meteor

React Native Router Flux and React Native Meteor inital Scene rendering Issue


Hi i need Help i have created an index page which checks if user is logged in or not and redirect accordingly and data is pass to that component via createContainer everything was working fine but now after logging in i have open Router Page and Redirecting from there All the components are routing properly except the components with withTracker i am again pushed to default initial screen

Walkthrough->

1.)Login Screen

2.)Shows Timesheets(initial in router)

3.)click Leaves->Apply Leave

4.)Tried opening Apply leave

5.)Opens For a second and then Back to initial Page(Timesheets)

index.js

`const myApp = (props) => {
  const { status, user, loggingIn } = props;
  if (status.connected === false || loggingIn) {
    // return <Loading />;
    return <RouterStack />
  } else if (user !== null) {
    // return <Home />
    return <RouterStack />
  }
  return <Login />
  };
  myApp.propTypes = {
  status: PropTypes.object,
  user: PropTypes.object,
  loggingIn: PropTypes.bool,
  };
  export default createContainer(() => {
  return {
    status: Meteor.status(),
    user: Meteor.user(),
    loggingIn: Meteor.loggingIn(),
  };
  }, myApp);
`

Router.js

`
export default class App extends Component {
  constructor(props) {
    super(props)
  }
  render() {
    return (
      <Router getSceneStyle={() => styles.sceneStyle}>
        <Scene key="root">
          <Scene key="Timesheets" component={Timesheets} title="Timesheets" initial />
          <Scene key="applyLeave" component={ApplyLeave} title="Apply Leave"  />
          <Scene key="Login" component={Login} title="Login" />
          <Scene key="Leaves" component={Leaves} title="Leave" />
          <Scene key="ViewLeave" component={LeaveHistory} title="Leaves History"/>
          <Scene key="Profile" component={Profile} title="Profile" />
        </Scene>
      </Router>
    )
  }
}
`

ApplyLeave.js

`class ApplyLeave extends Component {
render(){
return <View><Text></Text></View> //just for Demo
}
}
export default withTracker(params => {
    if (Meteor.user() != null) {
        const employeeId = Meteor.user();
        const leaves = Meteor.subscribe('leaves', employeeId);
        const entitlements=Meteor.subscribe('entitlements',employeeId);      
        return {
            myLeavesReady: leaves.ready(),
            myEntitlements: entitlements.ready()
        };
    }
    return {}
})(ApplyLeave);
`

Solution

  • The issue you are facing is actually a feature and shows that everything works fine (createContainer+ React).

    What happens is that one of your parameters in the return statement of the createContainer of myApp changes (or at least is reactively resent) and since myApp does not check whether it should re-render (shouldComponentUpdate) it does so by default => you're back on the initial screen.

    Steps to Perform to Fix Your Issue

    Now, this depends on whether you need the data that's being returned in the createContainer of myApp or not. If you need the data or need additional properties that come from Meteor.user() (e.g. profile information that may change), you will need to create your own shouldComponentUpdate and check if those values update.

    I don't think that that's the case for you so you will probably be fine with changing the props you're passing to the minimum that you actually need (without passing the user object - notice that Meteor.status() is also an object) and use PureComponent to prevent unwanted rerenders.

    class myApp extends React.PureComponent {
    
        render() {
            const { isConnected, isSignedIn, isSigningIn } = this.props;
            if (!isConnected || isSigningIn) {
                return <RouterStack />;
            } else if (isSignedIn) {
                return <RouterStack />;
            }
            return <Login />;
        }
    }
    
    myApp.propTypes = {
        isConnected: PropTypes.bool,
        isSignedIn: PropTypes.bool,
        isSigningIn: PropTypes.bool,
    };
    
    // if Meteor.something() is null, !!Meteor.something() is false
    // if Meteor.something() is a valid object, !!Meteor.something() is true
    export default createContainer(() => ({
        isConnected: !!Meteor.status().connected,
        isSignedIn: !!Meteor.user(),
        isSigningIn: !!Meteor.loggingIn(),  
    }), myApp);