Meteor / Reaction - How to wait for Meteor.user ()

I am trying to figure out how to wait for a Meteor.user() subscription in a react component. I know that the user is logged in because Meteor.userId() returns _id , but trying to access the email address show Meteor.user() returns undefined. I assume it is not yet available.

Alas, since Meteor.user () is not a publication that I manually sign, I am not sure how to wait for it in the React component. Can someone give me an example?

 import { Meteor } from 'meteor/meteor'; import React from 'react'; import { Link } from 'react-router'; import { createContainer } from 'meteor/react-meteor-data'; import './BaseLayout.scss'; class BaseLayout extends React.Component { constructor(props) { super(props); this.state = { isAuthenticated: (Meteor.userId() !== null) ? true : false, } } componentWillMount() { if (!this.state.isAuthenticated) { this.context.router.push('/login'); } } componentDidUpdate(prevProps, prevState) { if (!this.state.isAuthenticated) { this.context.router.push('/login'); } } toggleUserMenu() { this.refs.userMenu.style.display = (this.refs.userMenu.style.display === 'block') ? 'none' : 'block'; } logout(e) { e.preventDefault(); Meteor.logout(); this.context.router.push('/login'); } render() { return( <div id="base"> <div id="header"> <div id="top-bar" className="clear-fix"> <div className="float-left" id="logo"></div> <div className="float-right" id="user-menu"> <div onClick={this.toggleUserMenu.bind(this)}> <span>{this.props.currentUser.emails[0].address}</span> <div className="arrow-down"></div> </div> <div id="user-menu-content" ref="userMenu"> <a onClick={this.logout.bind(this)}>Sign Out</a> </div> </div> </div> </div> <div id="bodyContainer"> {this.props.children} </div> <div id="footer"> <ul> <li><a href="mailto: test@example.com ">Made by Us</a></li> </ul> </div> </div> ) } } BaseLayout.contextTypes = { router: React.PropTypes.object.isRequired, } export default BaseLayoutContainer = createContainer(() => { var handle = Meteor.subscribe("user.classrooms"); return { currentUser: Meteor.user(), dataLoading: !handle.ready(), classrooms: Classrooms.find({}).fetch(), }; }, BaseLayout); 
+8
source share
4 answers

You can use three-dimensional operation

 currentUser ? true : flase 

Also great advice to keep organized components always destructure , instead of doing const currentUser = this.props.currentUser , you can do const { currentUser } = this.props; Take a look:

 render() { const { currentUser, children } = this.props; return ( <div id="base"> <div id="header"> <div id="top-bar" className="clear-fix"> <div className="float-left" id="logo"></div> <div className="float-right" id="user-menu"> <div onClick={this.toggleUserMenu.bind(this)}> {currentUser ? <span>{currentUser.emails[0].address}</span> : <span>Loading...</span> } <div className="arrow-down"></div> </div> <div id="user-menu-content" ref="userMenu"> <a onClick={this.logout.bind(this)}>Sign Out</a> </div> </div> </div> </div> <div id="bodyContainer"> {children} </div> <div id="footer"> <ul> <li><a href="mailto: test@example.com ">Made by Us</a></li> </ul> </div> </div> ) } 
+4
source

The accepted answer is good, but after a while you will notice that you will have to repeat this many times on many components. Alternatively, you can listen to make sure the value of Accounts.loginServicesConfigured() true before even rendering on the top-level component using Tracker . Quoting meteorite documents: "The Accounts.loginServicesConfigured () function is a reactive data source that will return true after setting up the login service." I use a meteor, react, shorten and react the router.

 import React, { Component } from 'react'; import { Accounts } from 'meteor/accounts-base'; import { Route, Switch } from 'react-router-dom'; import { Tracker } from 'meteor/tracker'; class App extends Component { constructor(props) { super(props); this.state = { loading: true }; } componentWillMount() { Tracker.autorun(() => { if (Accounts.loginServicesConfigured()) { this.setState({ loading: false }); } }); } render() { return ( <div className="app"> { this.state.loading ? (<Spinner />) : ( <Route exact path="/" component={HomePage} /> ) } </div> ); } } 

Hope this alternative helps someone else. Good luck

+4
source

Add dataLoading :! handle.ready () ||! Meteor.user () in createContainer.

 export default BaseLayoutContainer = createContainer(() => { var handle = Meteor.subscribe("user.classrooms"); return { currentUser: Meteor.user(), dataLoading: !handle.ready() || !Meteor.user(), classrooms: Classrooms.find({}).fetch(), }; }, BaseLayout); 

Meteor.user() will be undefined inside the component before loading, so be sure to dataLoading ? "" : Meteor.user() it from being called by adding a condition like dataLoading ? "" : Meteor.user() dataLoading ? "" : Meteor.user() .

You can also check if the user is logged in !!Meteor.user() . Usually Meteor.userId() loads faster, but if you need to access user data, such as email, you need to call Meteor.user() , in which case you do not need to call both.

+1
source

Here are my 2 cents

Beware, if you use Meteor.user in, it may be undefined when you restart the server or in some other cases, so you need to check it, either an object or zero check documents on a meteor

Therefore, if I take the Roman answer, it should look like this.

 export default BaseLayoutContainer = createContainer(() => { var handle = Meteor.subscribe("user.classrooms"); var user = Meteor.user() return { currentUser: Meteor.user(), dataLoading: !handle.ready() || !(Accounts.loginServicesConfigured() && (user || user === null)), classrooms: Classrooms.find({}).fetch(), }; }, BaseLayout); 

Also, I think it’s a good idea to redirect the user to the login page or the restricted page if the user is null.

0
source

All Articles