如何使用钩子处理异步 firebase 调用

IT技术 reactjs firebase firebase-realtime-database async-await react-hooks
2021-05-20 01:53:21

我想创建一个用于将数据添加到 Firestore 数据库的挂钩。我不确定我是否误解了钩子的工作原理或 firestore 的工作原理,我对两者都是新手。

警告:无法对卸载的组件执行 React 状态更新。这是一个空操作,但它表明您的应用程序中存在内存泄漏。要修复,请取消 useEffect 清理函数中的所有订阅和异步任务。

火力基地API

  createTeam = newTeam => {
    return this.db.collection("teams").add({
      ...newTeam
    });
  };

钩子

export default function useFetch(action) {
  const [loading, setLoading] = useState(false);
  const [error, setError] = useState(null);
  const [data, setData] = useState(null);

  async function performAction(body) {
    try {
      setLoading(true);
      setData(null);
      setError(null);
      const data = await action(body);
      setData(data);
    } catch (e) {
      setError(e);
    } finally {
      setLoading(false);
    }
  }

  return [{ loading, data, error }, performAction];
}

零件

  const [state, runFetch] = useFetch(db.createTeam);
  const { values, handleChange, isDirty, handleSubmit } = useForm({
    initialValues: {
      name: "",
      location: ""
    },
    onSubmit({ values }) {
      runFetch(values);
    },
    validate(e) {
      return e;
    }
  });

state.data 从未设置为预期的响应,但是,fetch 挂钩中 await 之后的日志记录显示我正在接收响应。我应该在 useEffect 中这样做吗?通过 hooks/firebase 完成此任务的合适方法是什么?

1个回答

看看这是否适合你。

这是自定义钩子的好主意。

在此处输入图片说明

CodeSandbox 上的工作示例:

https://codesandbox.io/s/clever-joliot-ukr1t

索引.js

import React, { useState } from "react";
import ReactDOM from "react-dom";

import "./styles.css";

function App() {
  const [state, runFetch] = useFetch(mockAPICall);

  function mockAPICall() {
    return new Promise((resolve, reject) => {
      setTimeout(() => {
        resolve("Some data from DB!");
      }, 1000);
    });
  }

  return (
    <React.Fragment>
      <div>Loading: {state.loading ? "True" : "False"}</div>
      <div>Data: {state.data}</div>
      <button onClick={() => runFetch(mockAPICall)}>Get Data</button>
    </React.Fragment>
  );
}

function useFetch(action) {
  const [loading, setLoading] = useState(false);
  const [error, setError] = useState(null);
  const [data, setData] = useState(null);

  async function performAction(body) {
    try {
      setLoading(true);
      setData(null);
      setError(null);
      const data = await action(body);
      setData(data);
    } catch (e) {
      setError(e);
    } finally {
      setLoading(false);
    }
  }

  return [{ loading, data, error }, performAction];
}
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);