【问题标题】:Render is running before async method ends. How can i pass props to component from my async method?渲染在异步方法结束之前运行。如何从我的异步方法将道具传递给组件?
【发布时间】:2019-02-18 23:20:32
【问题描述】:

我需要将数据从 firestore 传递到我的组件中。但是请求是异步的,所以当我的渲染方法在我从请求中获取数据之前运行时,我遇到了问题。因此,当渲染运行时,pops 值为 Null,因为尚未定义状态。由于某种原因,组件也会渲染两次。 有没有更好的方法来处理异步的东西?

已经尝试过将请求放到更高的位置(index.js)并将数据传递给应用程序。 试图在渲染方法中发出请求。 试图将请求放在异步函数中并在构造函数中调用它以在那里设置状态。与调用异步方法相同。

class App extends Component {
constructor(props) {
    super(props);
    this.giveUsername = this.giveUsername.bind(this);

    const userId = firebase.auth().currentUser.email;
    this.giveUsername(userId);
}

async giveUsername(userId){
    let username;
    await firebase.firestore().collection('users').where('email', '==', userId).get().then((snapshot) =>{
        snapshot.docs.forEach(doc =>{
            console.log(`doc.data().username - ${doc.data().username}`);
            username = doc.data().username;
        });
    });
    this.setState( {
        userId : userId,
        username : username
    });
 }

render() {
    return (
      <div className='App'>
        <Header username={this.state.username}/>
        <NewTask userId={this.state.userId}/>
        <TaskList userId={this.state.userId}/>
      </div>
    );
}
}

【问题讨论】:

    标签: javascript reactjs firebase google-cloud-firestore


    【解决方案1】:

    渲染将在您获取数据之前运行,这是完全正常且正确的。检查数据是否为null 并呈现加载消息或什么都没有(return null

    【讨论】:

      【解决方案2】:

      你应该在构造函数中初始化state,这样你的组件即使没有数据也能正确渲染,并添加一个loading键来知道数据什么时候准备好,显示一个pinner会很有用

      constructor(props) {
          super(props);
          state = {
            userId : 0,
            username : '',
            loading: true
          }
      }
      

      当数据准备好时将loading设置为false

      async giveUsername(userId){
          ...
          this.setState( {
              userId : userId,
              username : username,
              loading: false
          });
       }
      

      渲染:

      render() {
          return (
            <div className='App'>
              {this.state.loading 
               ? <span>Loading ... </span> 
               : (
                   <Header username={this.state.username}/>
                   <NewTask userId={this.state.userId}/>
                   <TaskList userId={this.state.userId}/>
                 )
              }
            </div>
          );
      }
      

      组件渲染两次的原因是state 正在改变,这是正常的。

      【讨论】:

        【解决方案3】:

        发出请求时要了解的一般情况是,在您的组件开始时预计不会有任何数据,对此您无能为力。

        最佳做法是让用户知道数据正在加载。

        constructor(){
          this.state = {username: null, userId: null, loaded: false};
        }
        render() {
            return (
              <div className='App'>
                {
                   !this.state.loaded ? <p>Loading...</p> : 
        
                      <Header username={this.state.username}/>
                      <NewTask userId={this.state.userId}/>
                      <TaskList userId={this.state.userId}/>
                }
              </div>
            );
        }
        

        不要在控制器中获取请求!使用componentDidMount

        componentDidMount(){
            const userId = firebase.auth().currentUser.email;
            this.giveUsername(userId);
        }
        

        然后终于在giveUsername

        async giveUsername(userId){
            let username;
            await firebase.firestore().collection('users').where('email', '==', userId).get().then((snapshot) =>{
                snapshot.docs.forEach(doc =>{
                    console.log(`doc.data().username - ${doc.data().username}`);
                    username = doc.data().username;
                });
            });
            this.setState( {
                userId : userId,
                username : username,
                loaded: true
            });
         }
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2019-03-22
          • 1970-01-01
          相关资源
          最近更新 更多