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

时光毁灭记忆、已成空白 提交于 2019-12-04 03:25:37

You could use a ternary operation

currentUser ? true : flase

Also a great tip to keep components organized is to always destructure for example instead of doing const currentUser = this.props.currentUser you can do const { currentUser } = this.props; Have 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>
)
}

The accepted answer is good however after awhile you will notice that you will have to repeat this many times on many components. Alternatively you can listen to make sure that the Accounts.loginServicesConfigured() is true before even rendering at the top level component with Tracker. Quoting the meteor docs: "The function Accounts.loginServicesConfigured() is a reactive data source that will return true once the login service is configured". I am using meteor, react, redux, and react 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>
    );
  }
}

Hopefully this alternative helps someone else out. Good luck!

Add dataLoading: !handle.ready() || !Meteor.user() to the 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 make sure you prevent it's calling by adding a condition such as dataLoading ? "" : Meteor.user().

You can also check if user is logged in with !!Meteor.user(). Normally Meteor.userId() is faster to load but if you need to access user's data such as email you need to call Meteor.user() in that case no need to call both.

Here are mine 2 cents

Beware if you're using Meteor.user in can be undefined during server restart or some other cases so you need to check it it's either object or null check meteor docs

So if I take Rimskys's 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 probably a good idea to redirect the user to login or forbidden page if user is null.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!