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

时间:2019-07-04 21:18:06

标签: reactjs firebase firebase-realtime-database async-await react-hooks

我想创建一个将数据添加到Firestore数据库的钩子。我不确定是误解了钩子是如何工作的,还是firestore是如何工作的,我对这两者都是陌生的。

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

Firebase 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挂钩中等待后的日志记录显示我正在接收响应。我应该在useEffect中这样做吗?通过hook / firebase完成此任务的合适方法是什么?

1 个答案:

答案 0 :(得分:0)

查看是否适合您。

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

enter image description here

在CodeSandbox上的工作示例:

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

index.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);