如何在每次渲染时传入不同查询调用自定义Hook useFetch?
解决方案
问题的核心是:当currPage更新时,虽然你生成了新的Firestore查询对象,但useFetch自定义Hook没有检测到这个查询的变化,因此没有重新触发数据获取。下面是具体的修复步骤:
1. 修复useFetch的依赖监听
如果useFetch是你自己实现的自定义Hook,确保它内部的useEffect将传入的查询对象作为依赖项。这样当查询对象变化时,会自动重新执行数据请求。
示例实现:
import { useState, useEffect } from 'react'; import { getDocs, onSnapshot } from 'firebase/firestore'; function useFetch(query) { const [data, setData] = useState(null); const [mats, setMats] = useState(null); // 根据你的业务逻辑保留或调整 useEffect(() => { // 处理实时监听的取消逻辑(如果用了onSnapshot) let unsubscribe = null; const fetchData = async () => { if (!query) return; // 方式1:一次性获取数据 const snapshot = await getDocs(query); const result = snapshot.docs.map(doc => ({ id: doc.id, ...doc.data() })); setData(result); // 方式2:实时监听数据变化(如果需要) // unsubscribe = onSnapshot(query, (snapshot) => { // const result = snapshot.docs.map(doc => ({ // id: doc.id, // ...doc.data() // })); // setData(result); // }); }; fetchData(); // 清理函数:组件卸载或依赖变化时取消订阅 return () => { if (unsubscribe) unsubscribe(); }; }, [query]); // 关键:将query加入依赖数组,触发重新执行 return { data, setData, mats, setMats }; }
2. 优化查询传递逻辑(可选但推荐)
每次currPage变化时,query()会创建一个新的对象引用,即使currPage值相同,也可能触发不必要的重请求。你可以直接将currPage作为参数传入useFetch,在Hook内部构建查询,这样依赖项更明确:
修改后的useFetch:
function useFetch(collectionRef, filterField, filterValue) { const [data, setData] = useState(null); const [mats, setMats] = useState(null); useEffect(() => { let unsubscribe = null; const fetchData = async () => { if (!collectionRef || filterValue === undefined) return; // 内部构建查询 const q = query(collectionRef, where(filterField, "==", filterValue)); const snapshot = await getDocs(q); const result = snapshot.docs.map(doc => ({ id: doc.id, ...doc.data() })); setData(result); }; fetchData(); return () => { if (unsubscribe) unsubscribe(); }; }, [collectionRef, filterField, filterValue]); // 依赖是具体的原始值,避免引用变化问题 return { data, setData, mats, setMats }; }
在Crafts.js中调用:
const { data:crafts, setData:setCrafts, mats, setMats } = useFetch(craftsColRef, "category", currPage);
3. 确认父组件的状态更新逻辑
确保父组件中更新currPage时,是通过React的状态更新函数(比如useState的setter)来触发重渲染,而不是直接修改变量值。例如:
父组件示例:
import { useState } from 'react'; import Crafts from './Crafts'; function ParentComponent() { const [currPage, setCurrPage] = useState('default-category'); const handleNavClick = (category) => { setCurrPage(category); // 用setter更新状态,触发子组件重渲染 }; return ( <div> <button onClick={() => handleNavClick('woodcraft')}>木工</button> <button onClick={() => handleNavClick('pottery')}>陶艺</button> <Crafts currPage={currPage} /> </div> ); }
4. 调试验证
可以在Crafts.js和useFetch中添加日志,确认状态变化和查询执行情况:
// Crafts.js中 console.log('当前currPage:', currPage); // useFetch的useEffect中 console.log('查询已更新,重新获取数据');
内容的提问来源于stack exchange,提问作者glowbo
相关产品推荐
相关产品推荐

