React项目在回调内调用useAxios触发Hook规则报错该如何修复?
问题根因
- 违反React Hooks调用规则:React Hook必须在函数组件的顶层作用域调用,不能在事件回调、循环、条件判断等非顶层场景调用。你将
useAxios的调用放在表单提交的onFinish回调函数中,直接触发了react-hooks/rules-of-hooks校验规则,所以报错。 - 现有
useAxios设计不符合登录场景的需求:原有代码逻辑是Hook调用时就自动发起请求,但是登录请求需要用户填写完信息点击提交按钮后才触发,不能进入页面就自动发送。 - 额外隐藏问题:原有
useAxios中axios的传参顺序错误,post类请求的第二个参数是请求体body,第三个才是配置项headers,原代码顺序写反会导致请求参数传递异常。
修复方案
第一步:改造useAxios支持手动触发请求
调整Hook逻辑,新增自动请求开关,暴露请求方法供手动调用,同时修复参数顺序问题:
import { useState, useCallback, useEffect } from 'react'; import axios from 'axios'; axios.defaults.baseURL = 'http://localhost:3000/'; const useAxios = ({ url, method, body = null, headers = null, auto = true }) => { const [response, setResponse] = useState(null); const [error, setError] = useState(''); const [loading, setLoading] = useState(false); const fetchData = useCallback(async (customBody = body) => { setLoading(true); setError(''); try { let res; if (method.toLowerCase() === 'get') { res = await axios[method](url, headers); } else { res = await axios[method](url, customBody, headers); } setResponse(res.data); return res.data; } catch (err) { setError(err); throw err; } finally { setLoading(false); } }, [method, url, body, headers]); useEffect(() => { if (auto) { fetchData(); } }, [fetchData, auto]); return { response, error, loading, fetchData }; }; export default useAxios;
第二步:改造登录组件调用逻辑
在组件顶层调用useAxios,提交表单时调用暴露出来的请求方法即可:
import React from 'react'; import { Form, Input, Button, message } from 'antd'; import useAxios from '../hooks/useAxios'; const LoginForm = () => { // 组件顶层调用Hook,关闭自动请求开关 const { fetchData: login, loading } = useAxios({ url: 'api/auth/login', method: 'post', auto: false }); const onFinish = async (body) => { try { const loginResult = await login(body); console.log('登录成功', loginResult); // 此处可添加登录成功后的跳转、存储token等逻辑 } catch (err) { console.error('登录失败', err); message.error('账号或密码错误'); } }; const findIDAndPassword = () => { console.log('findIDAndPassword'); }; return ( <Form name="basic" onFinish={onFinish} autoComplete="off"> <Form.Item name="id" rules={[ { required: true, message: '请输入账号!', }, ]} > <Input placeholder="ID" /> </Form.Item> <Form.Item name="password" rules={[ { required: true, message: '请输入密码!', }, ]} > <Input.Password placeholder="PASSWORD" /> </Form.Item> <Form.Item> <Button type="primary" htmlType="submit" block loading={loading}> 登录 </Button> </Form.Item> <Button type="link" block onClick={findIDAndPassword}> 找回账号密码 </Button> </Form> ); }; export default LoginForm;
内容的提问来源于stack exchange,提问作者고윤태
相关产品推荐
相关产品推荐

