簡體   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