我没有将数据从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>
);
}
}
答案 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
});
}