gpt4 book ai didi

javascript - React 在 SetState 后不更新渲染

转载 作者:行者123 更新时间:2023-11-29 18:57:37 25 4
gpt4 key购买 nike

我已经研究代码一段时间了。我正在从 Firebase 获取数据并将该数据中的对象列表填充到此 UserProfile 页面上。我只是希望它能正常工作,以便当我进入个人资料页面时,那里会列出他们的项目列表。

问题是,使用此版本的代码,我必须单击配置文件链接两次才能显示项目,但显示名称显示正常。我知道 setState 是异步的。我试过在 setState 的回调中设置状态。我试过事先检查快照是否存在。我试过 componentDidMount 和 componentDidUpdate。这些都没有帮助,我只是以 this.state.items.map can't be called 或 newState 是一些空的、奇怪的东西而告终。我不知道我现在哪里错了。

当我对它进行控制台调试时,似乎正在调用 setState,但到目前为止还没有从 Firebase 获取任何内容,而且以后再也不会调用了。

也许我设置 newState 的方式有问题,因为当我尝试首次设置时,控制台日志 newState 为空。我只是不知道何时在适当的时间为第一次渲染设置它。

class UserProfile extends Component {
constructor(props){
super(props)
this.state = {
redirect: false,
userId: this.props.match.params.id,
displayName: "",
items: []
}
this.userRef = firebaseDB.database().ref(`/Users/${this.state.userId}`)
this.usersItemsRef = firebaseDB.database().ref(`/Users/${this.state.userId}/items`)
}

componentWillMount() {
this.userRef.on('value', snapshot => {
this.setState({
displayName: snapshot.val().displayName
});
});
this.usersItemsRef.on('value', snapshot => {
let usersItems = snapshot.val();
let newState = [];
for (let userItem in usersItems) {
var itemRef = firebaseDB.database().ref(`/items/${userItem}`)
itemRef.once('value', snapshot => {
var item = snapshot.val()
newState.push({
id: itemRef.key,
title: item.title
});
})
}
this.setState({
items: newState
})
});
}

componentWillUnmount() {
this.userRef.off();
this.usersItemsRef.off();
}

render() {
return (
<div style={{marginTop: "100px"}}>
<h1>{this.state.displayName}</h1>
<Link className="pt-button" aria-label="Log Out" to={"/submit_item/"+this.state.userId} >Submit an item</Link>
<section className='display-itemss'>
<div className="wrapper">
<ul>
{this.state.items.map((item) => {
return (
<li key={item.id}>
<h3>{item.title}</h3>
</li>
)
})}
</ul>
</div>
</section>
</div>
);
}
}

最佳答案

数据是从 Firebase 异步加载的,因为它可能需要不确定的时间。当数据可用时,Firebase 会调用您传入的回调函数。但此时您对 setState() 的调用早已完成。

查看此内容的最简单方法是在您的代码中添加一些日志语句:

componentWillMount() {
this.userRef.on('value', snapshot => {
this.setState({
displayName: snapshot.val().displayName
});
});
this.usersItemsRef.on('value', snapshot => {
let usersItems = snapshot.val();
let newState = [];
console.log("Before attaching once listeners");
for (let userItem in usersItems) {
var itemRef = firebaseDB.database().ref(`/items/${userItem}`)
itemRef.once('value', snapshot => {
console.log("In once listener callback");
var item = snapshot.val()
newState.push({
id: itemRef.key,
title: item.title
});
})
}
console.log("After attaching once listeners");
this.setState({
items: newState
})
});
}

此日志记录的输出将是:

Before attaching once listeners

After attaching once listeners

In once listener callback

In once listener callback

...

这可能不是您期望的顺序。但这完美地解释了为什么您的 setState() 不更新 UI:数据尚未加载。

解决方案是在数据加载完成后调用setState()。您可以通过将其移动**到*回调中来做到这一点:

componentWillMount() {
this.userRef.on('value', snapshot => {
this.setState({
displayName: snapshot.val().displayName
});
});
this.usersItemsRef.on('value', snapshot => {
let usersItems = snapshot.val();
let newState = [];
for (let userItem in usersItems) {
var itemRef = firebaseDB.database().ref(`/items/${userItem}`)
itemRef.once('value', snapshot => {
var item = snapshot.val()
newState.push({
id: itemRef.key,
title: item.title
});
this.setState({
items: newState
})
})
}
});
}

这将为加载的每个项目调用 setState()。通常,React 非常擅长处理此类增量更新。但以防万一它导致闪烁,您也可以使用 Promise.all() 等待所有项目加载:

componentWillMount() {
this.userRef.on('value', snapshot => {
this.setState({
displayName: snapshot.val().displayName
});
});
this.usersItemsRef.on('value', snapshot => {
let usersItems = snapshot.val();
let newState = [];
let promises = [];
for (let userItem in usersItems) {
var itemRef = firebaseDB.database().ref(`/items/${userItem}`)
promises.push(itemRef.once('value'));
}
Promise.all(promises).then((snapshots) => {
snapshots.forEach((snapshot) => {
var item = snapshot.val()
newState.push({
id: itemRef.key,
title: item.title
});
});
this.setState({
items: newState
});
});
});
}

关于javascript - React 在 SetState 后不更新渲染,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48655464/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com