自定义钩子返回值在组件中不会更改



我的自定义挂钩异步获取数据。当它在组件中使用时,返回的值不会更新。它一直显示默认值。有人知道发生了什么事吗?非常感谢。

import React, {useState, useEffect} from 'react'
import { getDoc, getDocs, Query, DocumentReference, deleteDoc} from 'firebase/firestore'
export const useFirestoreDocument = <T>(docRef: DocumentReference<T>) => {
const [value, setValue] = useState<T|undefined>(undefined)
const [isLoading, setIsLoading] = useState<boolean>(true)
const update = async () => {
const docSnap = await getDoc(docRef)
if (docSnap.exists()) {
const data = docSnap.data()
setValue(data)
}
setIsLoading(false)
}
useEffect(() => {
update()
}, [])
console.log(value, isLoading)  // it can shows correct data after fetching
return {value, isLoading}
}
import { useParams } from 'react-router-dom'
const MyComponent = () => {
const {userId} = useParams()
const docRef = doc(db, 'users', userId!)
const {value, isLoading} = useFirestoreDocument(docRef)
console.log(value, isLoading)  // keeps showing {undefined, true}.
return (
<div>
...
</div>
)
}

看起来youe钩子在渲染时只执行一次,因为它缺少作为依赖项的docRef

export const useFirestoreDocument = <T>(docRef: DocumentReference<T>) => {
const [value, setValue] = useState<T|undefined>(undefined)
const [isLoading, setIsLoading] = useState<boolean>(true)

useEffect(() => {
const update = async () => {
const docSnap = await getDoc(docRef)
if (docSnap.exists()) {
const data = docSnap.data()
setValue(data)
}
setIsLoading(false)
}
update()
}, [docRef])
console.log(value, isLoading)  // it can shows correct data after fetching
return {value, isLoading}
}

此外:如果您在其他地方不需要update函数定义,请将其放入useEffect挂钩中。否则,你的linter会抱怨deps的详尽规则。

useEffect挂钩缺少对docRef:的依赖项

export const useFirestoreDocument = <T>(docRef: DocumentReference<T>) => {
const [value, setValue] = useState<T|undefined>(undefined);
const [isLoading, setIsLoading] = useState<boolean>(true);

useEffect(() => {
const update = async () => {
setIsLoading(true);
try {
const docSnap = await getDoc(docRef);
if (docSnap.exists()) {
const data = docSnap.data();
setValue(data);
}
} catch(error) {
// handle any errors, log, etc...
}
setIsLoading(false);
};
update();
}, [docRef]);
return { value, isLoading };
};

渲染循环问题是因为docRefMyComponent中的每个渲染循环中都会重新声明。您应该记住这个值,以便将一个稳定的引用传递给useFirestoreDocument钩子。

const MyComponent = () => {
const {userId} = useParams();
const docRef = useMemo(() => doc(db, 'users', userId!), [userId]);
const {value, isLoading} = useFirestoreDocument(docRef);
console.log(value, isLoading);
return (
<div>
...
</div>
);
};

最新更新