Firebase 和 React Hooks(useState 和 useEffect)

Posted

技术标签:

【中文标题】Firebase 和 React Hooks(useState 和 useEffect)【英文标题】:Firebase and React Hooks (useState & useEffect) 【发布时间】:2020-03-23 16:20:35 【问题描述】:

我有一个基本的 react hooks 用法,但它似乎失败了。

错误

错误:无效的挂钩调用。

代码

function GetUserDisplayName(userId) 
  const [displayName, setDisplayName] = useState("Jane Doe");
  db.collection("users")
    .doc(userId)
    .get()
    .then(doc => 
      setDisplayName(doc.data().displayName);
    );
  return displayName;

注意,即使没有 db 调用,它也无法简单地返回默认的 displayName。

【问题讨论】:

将代码块放入try catch 并检查错误?该功能是功能组件内部的功能吗?为什么useState 钩子在那个函数里面? 您打算调用 firebase onMount 还是响应用户操作(如按钮单击)?下面techGuru的回答针对前者,我的回答针对后者。 我试图用用户名填充 dom - 它存储在用户集合中。这不需要用户操作。 【参考方案1】:

您发布的是一种方法,而不是自定义挂钩。按照惯例,所有挂钩都以“use”一词开头。如果要在挂钩中触发效果,则必须在自定义挂钩中使用 useEffect 挂钩。

import React,  useState, useEffect  from 'react';

function useDisplayName(userId) 
  const [displayName, setDisplayName] = useState("Jane Doe");

  useEffect(() => 
    db.collection("users")
    .doc(userId)
    .get()
    .then(doc => 
      doc.exists && 
      doc.data().displayName && 
      setDisplayName(doc.data().displayName);
    );
  , []);

  return displayName

下面的钩子将在初始化时运行,如componentDidMount,如果你想改变它,你可以在效果钩子的第二个参数中添加依赖项到数组中。 More info on that here

【讨论】:

您假设GetUserDisplayName 是一个功能组件?它可以是functional 组件内的method 吗? 钩子只能在功能组件中使用,不能在类组件中使用钩子。在类组件中,您可以使用常规的生命周期方法。 我知道,但我要说的是问题中提到的功能可以是功能组件内部的方法吗?不是主要组件 功能组件就是一个功能。为什么要将它包装在一个多余的额外 GetUserDisplayName 函数方法中?只需在功能组件中的 useEffect 挂钩中调用 firebase。 @JoshPittman 好像声明了“取消订阅”,但从未使用过?【参考方案2】:

我假设上面提供的函数是函数 component 中的 method

useState 应该在组件中的方法之外。

const yourComponent = () => 

const [displayName, setDisplayName] = useState("Jane Doe");

const GetUserDisplayName = (userId)  => 
  db.collection("users")
    .doc(userId)
    .get()
    .then(doc => 
      setDisplayName(doc.data().displayName);
    );
  return displayName;
 

return <p> INSERT JSX HERE</p>


【讨论】:

如果您不想使用任何生命周期方法,这个答案是完美的。例如,如果您想获取数据以响应按钮单击或其他操作。我假设问题是在生命周期方法的上下文中,否则根本不需要使用钩子。这只是一个普通的函数方法。 感谢您的澄清,我对 Firebase 不太熟悉,所以只是用谷歌搜索了一下,我完全同意你的看法!!!【参考方案3】:

尝试使用useEffect钩子

import React,  useState, useEffect  from "react";
import ReactDOM from "react-dom";

function useDisplayName(userId) 
  const [displayName, setDisplayName] = useState("Jane Doe");
  useEffect(() => 
    db.collection("users")
      .doc(userId)
      .get()
      .then(doc => 
        setDisplayName(doc.data().displayName);
      );
  , [userId]);

  return displayName;


function App() 
  const displayName = useDisplayName("Your ID");
  return <div>displayName</div>;


const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>

【讨论】:

以上是关于Firebase 和 React Hooks(useState 和 useEffect)的主要内容,如果未能解决你的问题,请参考以下文章

React Hooks 不适用于 Firebase Cloud Functions 错误:不变违规:无效的钩子调用

React + Firebase 使用钩子?

React Hooks + Firebase Firestore onSnapshot - 正确使用带有反应钩子的 Firestore 监听器

React Hooks:如何在 useEffect 中设置状态?

React-native hooks 表单验证

如何转换从@apollo/react-hooks 接收到的数据