我有一个非常基本的自定义钩子,该钩子采用从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内使用自定义钩子,或者我是否在做其他错误的事情。 / p>
答案 0 :(得分:1)
您当然可以在其他挂钩中调用挂钩。
请勿通过常规JavaScript函数调用Hook。相反,您可以:
✅从React函数组件中调用Hook。
✅从自定义挂钩中调用挂钩(我们将在下一页中了解它们)。
但是...
您没有在另一个挂钩中使用挂钩。
您意识到传递给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的答案返回后续渲染的文档。
答案 1 :(得分:0)
据我所知,组件中的钩子应始终保持相同顺序。而且由于useEffect
有时会发生,并且并非每个渲染都违反了钩子规则。在我看来,您的useGetDocument
并没有真正的需要。
我提出以下解决方案:
useGetDocument
不变。useEffect
作为依赖项的document
。您的组件可能如下所示:
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 (...)
}
答案 2 :(得分:0)
您不能在另一个挂钩中使用一个挂钩,因为它违反了规则Call Hooks from React function components
,并且您传递给useEffect
的函数是常规的javascript函数。
您可以做的是在另一个自定义钩子内调用钩子。
您需要做的是在组件内部调用useGetDocument
并将结果传递到useEffect
依赖项数组中。
let docSnapshot = await useGetDocument("products/" + products[selectedProduct].id + "labels/list")
useEffect(() => { ... }, [docSnapshot])
这样,当docSnapshot
发生变化时,您的useEffect
就会被呼叫。