渲染在异步方法结束之前正在运行。如何通过我的异步方法将props传递给组件?

时间:2019-02-18 23:20:32

标签: javascript reactjs firebase google-cloud-firestore

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

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

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

4 个答案:

答案 0 :(得分:0)

惯例通常是调用将从componentDidMount()而不是constructor()方法设置组件的函数。

此外,您的async await函数中的giveUsername()不在等待Promise.then()。解决方案是同时使用 或。

在处理不确定数据时,也建议为this.state设置一个初始值。

请参见下面的实际示例。

class App extends Component {

  constructor(props) {
    super(props);
    this.state = {
      username: undefined,
      userId: undefined
    };
    this.giveUsername = this.giveUsername.bind(this);
  }

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

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

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

}

答案 1 :(得分:0)

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

答案 2 :(得分:0)

您应该在构造函数中初始化state,以便即使没有数据也可以正确呈现组件,并添加一个loading键以知道何时数据准备就绪,这将有助于显示固定器

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 :(得分:0)

发出请求时要了解的一般情况是,期望在组件的开头没有任何数据,并且您对此无能为力。

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

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