javascript - 如何使用钩子(Hook)将 React 类组件转换为函数组件以获取 firebase 数据

标签 javascript reactjs firebase firebase-realtime-database react-hooks

我有一个正在工作的 React 类组件,我想将其转换为功能组件以使用钩子(Hook)进行状态等。我正在学习 React 钩子(Hook)。类组件版本工作正常,功能组件是我需要帮助的地方。

数据结构由具有三个“客户端”的客户端列表组成。它的图像在这里:

enter image description here

我想做的就是获取这些数据,迭代它并向用户显示每个名称键的数据。够简单的。

问题是从我的组件调用 firebase 会导致不稳定的行为,因为无法正确检索数据。连续调用最后一个客户端名称,导致浏览器卡住。 :)

这是结果的图像:

enter image description here

这是代码:



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/

相关文章:

javascript - 如何区分 promise 链中的操作错误和程序员错误?

javascript - 在不更改时间部分的情况下更新 javascript 对象的日期部分

javascript - 如何异步运行 useState

java - 无法从 firestore 中检索已经存在的图像 uri

javascript - 我可以将 x-template 脚本导入 HTML 文件吗?

reactjs - 如何在 react 传单中更改具体国家/地区的颜色/边框颜色

javascript - 如何使用 react 检查元素是否存在?

Firebase 动态链接 : Increase Custom Domain Limit

java - 无法使用 Push Id Firebase 弹回输入

javascript - 单个 JavaScript 对象列表到适当的数组