2016-09-18 103 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> 
    ); 
    } 
} 

希望這種替代方法可以幫助別人。祝你好運!