从Firebase读取数据时,似乎我遇到setState
的某种竞争条件。加载组件后,将调用侦听器child_added
,因为客户端记录位于表clients
中,但只有最后一个客户端记录实际存储在使用setState
的状态中。我知道这与setState中的延迟有关,它只在循环结束时才起作用,因此存在多个setState调用的竞争条件。如何解决此问题,以便所有客户记录都正确存储在this.state.clients
?
class ClientsTable extends React.Component {
constructor(props) {
super(props);
this.state = {
open: false,
clients: [],
};
}
componentWillMount(){
let clientsRef = fire.database().ref('clients').orderByKey().limitToLast(100);
clientsRef.on('child_added', snapshot => {
let client = snapshot.val();
client.id = snapshot.key
this.setState({ clients: [client].concat(this.state.clients) })
})
}
}
答案 0 :(得分:0)
不应该出现任何竞争条件,因为setState()
每次调用时都会更改一次,在这种情况下,每个client
快照都会由{{1}生成}事件包括已添加的现有child_added
和新client
。
问题实际上可能与client
的语法有关,每次都可能会突变/恢复setState()
。相反,请尝试使用this.state.clients
spread syntax
将...
个对象追加到client
并以不可变的方式更新/合并this.state.clients
。
this.state
使用个人Firebase项目,我能够将每个项目都等同于class ClientsTable extends React.Component {
constructor(props) {
super(props);
this.state = {
open: false,
clients: []
};
}
componentWillMount(){
const clientsRef = fire.database().ref('clients').orderByKey().limitToLast(100);
clientsRef.on('child_added', snapshot => {
const client = { ...snapshot.val(), id: snapshot.key };
this.setState({
...this.state,
clients: [...this.state.clients, client]
});
});
}
}
,并在this.state.clients
或componentDidMount
中相应地显示这些项目。如果您愿意,可以创建一个虚拟Firebase项目,其模拟数据/结构与您的实际项目相匹配,如果它仍然不起作用,则生成StackBlitz。
希望这有帮助!
答案 1 :(得分:0)
问题是您需要清除对Firebase的引用,否则将导致内存泄漏。在React中,通常是在 componentWillUnmount 中完成的。
使用您的示例,您需要添加以下内容:
componentWillUnmount: function() {
this.clientsRef.off();
}
您还需要在 componentDidMount 中修改代码,以便使用 this.clientsRef 使用局部变量的说明。
您可以在Firebase Blog上了解有关此内容的更多信息。