我有一个正在工作的 React 类组件,我想将其转换为功能组件以使用钩子(Hook)进行状态等。我正在学习 React 钩子(Hook)。类组件版本工作正常,功能组件是我需要帮助的地方。
数据结构由具有三个“客户端”的客户端列表组成。它的图像在这里:
我想做的就是获取这些数据,迭代它并向用户显示每个名称键的数据。够简单的。
问题是从我的组件调用 firebase 会导致不稳定的行为,因为无法正确检索数据。连续调用最后一个客户端名称,导致浏览器卡住。 :)
这是结果的图像:
这是代码:
import React, {Component,useContext,useEffect, useState} from 'react';
import PropTypes from 'prop-types';
import { withStyles } from '@material-ui/core/styles';
import Paper from '@material-ui/core/Paper';
import Grid from '@material-ui/core/Grid';
import ListItem from '@material-ui/core/ListItem';
import Button from '@material-ui/core/Button';
import firebase from 'firebase/app';
import {Consumer,Context} from '../../PageComponents/Context';
const styles = theme => ({
root: {
flexGrow: 1,
},
paper: {
padding: theme.spacing.unit * 2,
textAlign: 'center',
color: theme.palette.text.secondary,
},
});
const FetchData = (props) =>{
const [state, setState] = useState(["hi there"]);
const userID = useContext(Context).userID;
useEffect(() => {
let clientsRef = firebase.database().ref('clients');
clientsRef.on('child_added', snapshot => {
const client = snapshot.val();
client.key = snapshot.key;
setState([...state, client])
});
});
//____________________________________________________BEGIN NOTE: I am emulating this code from my class component and trying to integrate it
// this.clientsRef.on('child_added', snapshot => {
// const client = snapshot.val();
// client.key = snapshot.key;
// this.setState({ clients: [...this.state.clients, client]})
// });
//___________________________________________________END NOTE
console.log(state)
return (
<ul>
{
state.map((val,index)=>{
return <a key={index} > <li>{val.name}</li> </a>
})
}
</ul>
)
}
FetchData.propTypes = {
classes: PropTypes.object.isRequired
}
export default withStyles(styles)(FetchData)
最佳答案
默认情况下,useEffect
回调在每次完成渲染( see docs )后运行,并且您在每次调用时设置一个新的 firebase 监听器。因此,当 Firebase 发出事件时,每个此类监听器都会收到数据快照,并且每个监听器都会将接收到的值添加到状态中。
相反,您需要在安装组件后设置监听器一次,可以通过提供依赖项的空数组 ( []
) 作为 useEffect
的第二个参数来实现此目的。 :
useEffect(() => {
// your code here
}, []) // an empty array as a second argument
这将告诉 React 该效果没有任何依赖项,因此无需多次运行它。
但是还有一个重要时刻。由于您设置了监听器,因此您需要在不再需要它时清理它。这是通过另一个回调完成的,您应该在传递给 useEffect
的函数中返回该回调。 :
useEffect(() => {
let clientsRef = firebase.database().ref('clients');
clientsRef.on('child_added', snapshot => {
const client = snapshot.val();
client.key = snapshot.key;
setState([...state, client])
});
return () => clientsRef.off('child_added') // unsubscribe on component unmount
}, []);
基本上,这个返回的清理函数将在调用每个新效果之前以及组件卸载( see docs )之前调用,因此只有这个清理函数应该自行解决您的解决方案,但无需在每次之后调用您的效果无论如何渲染 []
作为第二个参数。
关于javascript - 如何使用钩子(Hook)将 React 类组件转换为函数组件以获取 firebase 数据,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55446167/