如何让自定义Hook依赖React Query的useQuery Hook执行?
解决React Hook条件调用错误的方案
问题原因
React Hook的核心规则要求:所有Hook必须在组件的顶层作用域调用,不能放在条件判断、循环或嵌套函数中。你尝试把useProductData放在isLoading判断之后,属于条件调用,违反了Hook的调用顺序规则,因此触发报错。
解决方案:让Hook兼容未加载状态
修改useProductData,使其能够处理products为undefined的情况,这样就可以在组件顶层安全调用该Hook,无需条件判断。
修改后的useProductData.js
import { useState } from "react"; function useProductData(products) { // 当products未加载完成时,返回默认结构避免报错 if (!products) { return { filteredValues: [], checkedBrands: {}, products: [], title: "Crowlers", brandFilterData: { uniqueBrands: [], checkedBrands: {}, setCheckedBrands: () => {} }, priceFilterData: { min: 0, max: 0, filteredValues: [], setFilteredValues: () => {} }, isVoucher: false }; } const brands = products.map(({ id, brand }) => ({ id, brand, })); const prices = products.map((item) => item.price); const min = Math.min(...prices); const max = Math.max(...prices); const title = "Crowlers"; // TODO const uniqueBrands = brands.filter( (item, index, self) => index === self.findIndex((t) => t.brand === item.brand) ); const [filteredValues, setFilteredValues] = useState([min, max]); const [checkedBrands, setCheckedBrands] = useState({}); const brandFilterData = { uniqueBrands, checkedBrands, setCheckedBrands }; const priceFilterData = { min, max, filteredValues, setFilteredValues }; const isVoucher = products.every((product) => product.name.includes("Voucher") ); return { filteredValues, checkedBrands, products, title, brandFilterData, priceFilterData, isVoucher, }; } export default useProductData;
保持Catalogue.jsx不变
import { Box, Spinner } from "@chakra-ui/react"; import ProductPage from "../../components/Products/ProductPage"; import useBeers from "../../hooks/useBeers"; import useProductData from "../../hooks/useProductData"; const Catalogue = () => { const { data: products, isLoading } = useBeers(); // 顶层调用Hook,完全符合React规则 const productData = useProductData(products); if (isLoading) return <Spinner />; return ( <Box> <ProductPage productData={productData} /> </Box> ); }; export default Catalogue;
原理说明
通过在useProductData中提前判断products是否存在,当数据未加载时返回安全的默认值,既保证了Hook始终在组件顶层调用,又避免了执行map、Math.min等依赖products存在的代码而导致的报错。当isLoading结束后,products数据就绪,Hook会自动返回正确的计算结果。
内容的提问来源于stack exchange,提问作者ivsheva
相关产品推荐
相关产品推荐

