繁体   English   中英

是否可以在 React 的 useEffect 中使用自定义挂钩?

[英]Is it possible to use a custom hook inside useEffect in React?

我有一个非常基本的自定义挂钩,它接受一个路径并从 firebase 返回一个文档

import React, { useState, useEffect, useContext } from 'react';
import { FirebaseContext } from '../sharedComponents/Firebase';

function useGetDocument(path) {
    const firebase = useContext(FirebaseContext)
    const [document, setDocument] = useState(null)

    useEffect(() => {
        const getDocument = async () => {
            let snapshot = await firebase.db.doc(path).get()
            let document = snapshot.data()
            document.id = snapshot.id
            setDocument(document)
        }
        getDocument()
    }, []);

    return document
}

export default useGetDocument

然后我使用 useEffect 作为 componentDidMount/constructor 来更新状态

useEffect(() => {
    const init = async () => {

      let docSnapshot = await useGetDocument("products/" + products[selectedProduct].id + "labels/list")
      if(docSnapshot) {
        let tempArray = []
        for (const [key, value] of Object.entries(docSnapshot.list)) {
          tempArray.push({id: key, color: value.color, description: value.description})
        }
        setLabels(tempArray)
      } else {
        setLabels([])
      }

      await props.finishLoading()
      await setLoading(false)
    }
    init()
  }, [])

但是,我从“throwInvalidHookError”得到了一个不变的违规,这意味着我违反了钩子的规则,所以我的问题是你是否不能在 useEffect 中使用自定义钩子,或者我是否做错了其他事情。

据我所知,组件中的钩子应该始终保持相同的顺序。 而且由于useEffect有时会发生,并不是每个渲染都违反hooks 的规则 在我看来,您的useGetDocument没有真正的需要。

我提出以下解决方案:

  1. 保持你的useGetDocument不变。
  2. 将您的组件更改为具有将document作为依赖项的useEffect

您的组件可能如下所示:

const Component = (props) => {
    // Your document will either be null (according to your custom hook) or the document once it has fetched the data.
    const document = useGetDocument("products/" + products[selectedProduct].id + "labels/list");

    useEffect(() => {
        if (document && document !== null) {
            // Do your initialization things now that you have the document.
        }
    }, [ document ]);

   return (...)
}

您不能在另一个钩子中使用一个钩子,因为它打破了Call Hooks from React function components的规则,并且您传递给useEffect的函数是一个常规的 javascript 函数。

您可以做的是在另一个自定义挂钩中调用一个挂钩。

您需要做的是在组件内部调用useGetDocument并将结果传递到useEffect依赖项数组中。

let docSnapshot = await useGetDocument("products/" + products[selectedProduct].id + "labels/list")

useEffect(() => { ... }, [docSnapshot])

这样,当docSnapshot发生变化时,您的useEffect就会被调用。

当然你可以在其他的钩子中调用钩子。

不要从常规 JavaScript 函数调用 Hooks。 相反,您可以:

✅ 从 React 函数组件调用 Hooks。

✅ 从自定义 Hooks 调用 Hooks(我们将在下一页了解它们)。

但...

您没有在另一个钩子中使用一个钩子

您意识到您传递给 useEffect 的是一个回调,因此您在回调主体内使用自定义挂钩而不是挂钩 (useEffect)。

如果你碰巧使用 ESLint 和 react-hooks 插件,它会警告你:

ESLint: React Hook "useAttachDocumentToProspectMutation" cannot be called inside a callback. React Hooks must be called in a React function component or a custom React Hook function.(react-hooks/rules-of-hooks)

话虽这么说,你根本不需要 useEffect 。 useGetDocument 不返回承诺,而是返回文档。

挂钩时

const document = useGetDocument("products/" + products[selectedProduct].id + "labels/list");

它将第一次返回 undefined ,然后根据@ApplePearPerson 的回答返回后续渲染的文档。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM