React调用自定义useFetch Hook出现导入及无效Hook调用问题求助
问题1:初始的useFetch导入错误
触发该报错的排查方向:
- 确认
useFetch文件的相对路径和导入路径完全匹配,比如Patient组件存放在src/pages/Patient.js、useFetch存放在src/hooks/useFetch.js的场景下,导入路径需要对应写为import useFetch from '../hooks/useFetch',路径拼写错误会触发导出不存在的报错 - 确认导出和导入语法匹配:你最初的useFetch是
export default默认导出,对应的导入必须是默认导入写法,不能给useFetch加花括号,加花括号是命名导出的导入写法,写错会触发该报错。
问题2:修改后的Hook无效调用报错
该报错的直接原因是违反了React的Hook使用规则:Hook只能在函数组件的顶层、或者其他自定义Hook内部调用,不能在类组件的生命周期方法、类方法、普通函数内部调用。你当前的Patient是类组件,在componentDidMount生命周期里调用自定义HookuseFetch,自然触发报错。
两种解决方案按需选择:
方案1:把Patient组件改写成函数组件(推荐,符合Hook使用规范)
改写后的组件代码示例:
import React from 'react'; import useFetch from "../useFetch"; export default function Patient() { // 必须在函数组件顶层调用Hook const [ response, loading, hasError ] = useFetch("/Patient/GetPatients", {}); if (loading) return <div>加载中...</div> if (hasError) return <div>加载失败</div> return ( <div> {/* 渲染获取到的response数据 */} {JSON.stringify(response)} </div> ); } Patient.displayName = Patient.name;
同时你修改后的useFetch存在解析响应的bug,原生fetch返回的响应对象没有data属性,需要先调用.json()解析,修正后的useFetch代码:
import React, { useEffect, useState } from "react"; export default function useFetch(url, opts){ const [response, setResponse] = useState(null) const [loading, setLoading] = useState(false) const [hasError, setHasError] = useState(false) useEffect(() => { if (!url) return; setLoading(true) fetch(url, opts) .then((res) => res.json()) // 新增响应解析逻辑 .then((data) => { setResponse(data) setLoading(false) }) .catch(() => { setHasError(true) setLoading(false) }) }, [url, opts]) return [response, loading, hasError] }
方案2:保留类组件的话,直接在生命周期里写请求逻辑,不要使用自定义Hook
import React, { Component } from 'react'; export class Patient extends Component { static displayName = Patient.name; constructor(props) { super(props); this.state = { loading: false, response: null, hasError: false } } componentDidMount() { this.setState({loading: true}) fetch("/Patient/GetPatients") .then(res => res.json()) .then(data => { this.setState({ response: data, loading: false }) }) .catch(() => { this.setState({ hasError: true, loading: false }) }) } render() { const {loading, response, hasError} = this.state if (loading) return <div>加载中...</div> if (hasError) return <div>加载失败</div> return ( <div> {JSON.stringify(response)} </div> ); } }
内容的提问来源于stack exchange,提问作者redoc01
相关产品推荐
相关产品推荐

