简体   繁体   English

渲染在异步方法结束之前运行。 如何将道具从我的异步方法传递给组件?

[英]Render is running before async method ends. How can i pass props to component from my async method?

I neet to pass data from firestore into my components.我需要将数据从 firestore 传递到我的组件中。 But request is async so i stuck on problem when my render method runs before i get data from my request.但是请求是异步的,所以当我的渲染方法在我从我的请求中获取数据之前运行时,我遇到了问题。 So when the render runs the pops value is Null because state is not defined yet.因此,当渲染运行时,pops 值为 Null,因为尚未定义状态。 Also component for some reason renders twice.由于某种原因,组件也呈现两次。 Is there any better way to handle async stuff?有没有更好的方法来处理异步的东西?

Already tried po put request to firestore in higher place (index.js) and pass data down to app.已经尝试将请求放在更高位置的 firestore (index.js) 并将数据传递给应用程序。 Tried to make request inside render method.试图在渲染方法中发出请求。 Tried to put request inside async function and call it in constructor to set state there.试图将请求放入异步函数并在构造函数中调用它以在那里设置状态。 Same thing as calling async method.与调用异步方法相同。

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

The convention is typically to call functions that will set your components up from componentDidMount() , rather than the constructor() method. 约定通常是调用将通过componentDidMount()而不是constructor()方法来设置组件的constructor()

Also, the async await in your giveUsername() function is not waiting for the Promise.then() . 另外,您的giveUsername()函数中的async await未等待Promise.then() The solution is to use either , rather than both. 解决的办法是要么使用,而不是两个。

Setting an initial value for this.state is also recommended when dealing with indeterminate data. 在处理不确定数据时,还建议为this.state设置初始值。

See below for a practical example. 请参见下面的实际示例。

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

}

Render will run before you get your data, that's totally normal and correct. 渲染将在您获取数据之前运行,这完全正常且正确。 Check if the data is null and render a loading message or nothing ( return null ) 检查数据是否为null并呈现加载消息或什么都不显示( return null

you should initialize the state in the constructor so your component renders properly even without data, and add a loading key to know when the data are ready, and it would be useful to show a pinner 您应该在构造函数中初始化state ,以便即使没有数据也可以正确呈现组件,并添加loading键以知道数据何时准备就绪,这对于显示固定器很有用

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

set the loading to false when data are are ready : 当数据准备好时,将loading设置为false

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

Render : 渲染:

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

and the reason why the component is rendering twince is because the state is changing and that's normal. 组件呈现缠绕的原因是因为state在变化,这是正常的。

The general thing to understand when making requests is that, it's expected that there won't be any data at the start of your component and there is nothing you can do about that. 发出请求时要了解的一般情况是,预计组件的开头不会有任何数据,对此您无能为力。

Best practices is to let the user know that the data is loading. 最佳做法是让用户知道数据正在加载。

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

Do not do fetch requests in your controller ! 不要在控制器中获取请求! Use componentDidMount 使用componentDidMount

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

Then finally in giveUsername 然后终于在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
    });
 }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM