2016-09-18 59 views
5

我正在努力弄清楚如何在反应组件中等待Meteor.user()订阅。我知道用户已登录,因为Meteor.userId()返回_id,但试图访问电子邮件地址显示Meteor.user()返回未定义。我假设,因为它尚不可用。流星/反应 - 如何等待Meteor.user()

唉,由于Meteor.user()不是我手动订阅的发布,我不确定如何在React组件中等待它。有人能指点我一个例子吗?

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:[email protected]">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); 

回答

4

你可以使用一个三元操作

currentUser ? true : flase 

也是一个很大的提示,以保持组织的成分是始终destructure例如,而不是做const currentUser = this.props.currentUser你可以做const { currentUser } = this.props;看一看:

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:[email protected]">Made by Us</a></li> 
     </ul> 
    </div> 
    </div> 
) 
} 
+0

我喜欢它,当答案是明显的,只是希望我会看到它!非常感谢你提供关于解构的提示,我可以看到它将如何保持标记更清洁和更少依赖。再次感谢! – Scott

+0

很高兴我可以帮忙@DMX谢谢! –

1

添加数据加载:!handle.ready()|| !Meteor.user()到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()将在组件内部装载所以一定要防止它的加入条件,如dataLoading ? "" : Meteor.user()调用之前是不确定的。

您还可以检查用户是否使用!!Meteor.user()登录。通常Meteor.userId()的加载速度更快,但如果您需要访问用户的数据(例如电子邮件),那么在这种情况下您需要拨打Meteor.user(),无需同时拨打电话。

1

接受的答案是好的,但过了一段时间后,您会注意到您将不得不在许多组件上重复这么多次。或者,您可以在Tracker顶级组件上渲染前确保Accounts.loginServicesConfigured()为真。引用meteor文档:“Accounts.loginServicesConfigured()函数是一个被动数据源,一旦配置了登录服务,它将返回true”。我正在使用流星,反应,还原和反应路由器。

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> 
    ); 
    } 
} 

希望这种替代方法可以帮助别人。祝你好运!