reactjsmeteorauthenticationstatemeteor-1.4

Meteor and React: Correct way to render according to login state


I have a Meteor + React application with login functionality. The main navigation bar displays different items depending on the login state of the user.

My problem is that when a user logs in it doesn't automatically update the navigation bar like expected. It only shows after the page is reloaded or the route is changed.

This obviously goes against the greatness of using React.

This is what I have:

AppContainer

export class AppContainer extends Component {
    constructor(props) {
        super(props)
        this.state = this.getMeteorData()
    }

    getMeteorData() {
        return { isAuthenticated: Meteor.userId() !== null}
    }

    render() {
        return(
            <div className="hold-transition skin-green sidebar-mini">
                <div className="wrapper">
                    <Header isAuthenticated={this.state.isAuthenticated} />
                    <MainSideBar />
                    {this.props.content}
                    <Footer />
                    <ControlSideBar />
                    <div className="control-sidebar-bg"></div>
                </div>
            </div>
        )
    }
}

Header

export class Header extends Component {
    render() { 
        return (
            <header className="main-header">
                ...
                <nav className="navbar navbar-static-top" role="navigation">
                    <a href="#" className="sidebar-toggle" data-toggle="offcanvas" role="button">
                        <span className="sr-only">Toggle navigation</span>
                    </a>
                    <CustomNav isAuthenticated={this.props.isAuthenticated} />
                </nav>
            </header>
        )
    }
}

CustomNav

export class CustomNav extends Component {
    render() {
        if(this.props.isAuthenticated) {
            navigation = <NavLoggedIn />
        } else {
            navigation = <NavLoggedOut />
        }
        return (
            <div className="navbar-custom-menu">
                {navigation}
            </div>
        )
    }
}

I think that's all the relevant code needed to help solve this but let me know if I should be doing something else. Not sure if passing the props down through the components like I am is the correct thing to do either so give me a heads up if I'm messing up there too please.

Help is much appreciated!


Solution

  • You need to wrap your Component to use Meteor's reactive data.

    AppContainer.propTypes = {
       user: PropTypes.object,
    };
    
    export default createContainer(() => {
      return {
        user: Meteor.user(),
      };
    }, AppContainer);
    

    The user object will be stored in this.props.user. You can use it to conditionally render views.