javascript - React setState 在获取数据后不会重新渲染
问题描述
如果已获取数据,则此代码有效。
但是如果我刷新页面并且不重新渲染元素,则不起作用。
如果值得一提,我也在使用 Next JS。
class Books extends Component {
constructor(props) {
super(props);
this.state = {
book: []
}
this.renderBooks= this.renderBooks.bind(this);
}
renderBooks() {
let item;
let items = [];
return new Promise((resolve, reject) => {
this.props.ids.forEach(address => {
firebase.database().ref(`/books/${address}`)
.on('value', snap => {
item = snap.val();
});
items.push(item);
})
resolve(items);
});
}
async componentDidMount() {
try {
let res = [];
res = await this.renderBooks();
console.log(res);
this.setState({ book: res });
} catch (error) {
console.log(error);
this.setState(prevState => {
return { book: 'err' }
});
}
}
render() {
return (
<div>
{ <List grid={{ gutter: 16 }}
dataSource={ this.state.book }
renderItem={ item => (
<List.Item>
<Card title={ !!item && item.title }>
...Book content...
</Card>
</List.Item>
)} />
}
</div>
);
}
}
export default Books;
关于 setState 和获取我在这里错过的数据有什么要了解的吗?
PS。编辑构造函数以预订:[]。
解决方案
您不能book
使用承诺进行初始化。相反,您可以有如下解决方案。
为您的方法添加条件渲染,render
以便它知道何时渲染book
。new Promise
在这种情况下,您也不需要返回。
class Books extends Component {
constructor(props) {
super(props);
this.state = { books: null }
}
componentDidMount() {
this.renderBooks()
}
renderBooks() {
this.props.ids.forEach(address => {
firebase.database().ref(`/books/${address}`)
.on('value', snap => {
this.setState({books: [...(this.state.books || []), snap.val()] });
});
});
}
render() {
return (
this.state.books ?
<div>
{ <List grid={{ gutter: 16 }}
dataSource={ this.state.books }
renderItem={ item => (
<List.Item>
<Card title={ !!item && item.title }>
...Book content...
</Card>
</List.Item>
)} />
}
</div>
: 'Initializing'
);
}
}
export default Books;
Promise 基本上是异步函数,在适当的时候解决。
所以当你这样做时
var item, items = []; // <---- Step 1
this.props.ids.forEach(address => {
firebase.database().ref(`/books/${address}`)
.on('value', snap => {
item = snap.val(); // <--- Step 3
});
});
items.push(item); // <----- Step 2
});
步骤是这样的。items.push(item)
因此,您在 item 被分配一个新值之前所做的是snap.val()
. 这使得item
undefined
.
我想你得到的第二个结果是由于缓存。如果 Internet 连接速度很快,则Step 3
可能早于Step 2
,但这是一个错误的假设。这就是为什么您第二次得到正确结果的原因。
在这个答案的情况下,不是有一个items
数组,snap.val()
而是添加到 this.state.books 中。但这使它有点重量级。因为每次on('value')
调用查询时,setState
都会触发该方法,再次渲染组件。如果有 1000 个 id,则状态将更改 1000 次。
这就是为什么我建议您一次获取所有数据,而不是一一获取数据。尝试用谷歌搜索类似'retrieve multiple data from firebase javascript'
. 不幸的是,我对firebase知之甚少,因此无法提供帮助。
推荐阅读
- karate - 当帖子 'content-type' 是 application/x-www-form-urlencoded 并且 * form field param= {
} - python - 有没有办法在 Azure Databricks 中动态地将参数传递给作业?
- c# - 如何使用 C# 将 `xmlns` 重命名为 TYPE
- python - django-celery 接收任务但不执行它
- javascript - elasticsearch中如何将url参数添加到elasticsearch UpdateByQuery
- google-apps-script - 当我在单元格 A1 中进行任何更改时,如何将单元格 A2 的值更改为“Today()”?
- php - 在使用 php 向用户显示之前更改网页内容
- c# - 转换为 JSON 时,@ 符号出现在 XML 的属性之前
- javascript - Vanilla Javascript 类中的“计算属性”
- php - 如何从我的一个数据库表的 id (pk) 比较 request->id?