React中创建可复用API请求函数的方法及最佳实践咨询
问题描述
需要在独立JavaScript文件中创建可复用函数,通过GET方法向API传递两个参数(JSON格式),获取返回的JSON数据并在home.js中使用,同时想了解React中的最佳实践。
请求参数格式:
{ "exam_id": 1, "question_id": 22 }
预期返回格式:
[ { "Choice_1": "choice 1", "Choice_2": "choice 2", "Choice_3": "choice 3", "Choice_4": "choice 4", "Choice_5": "choice 5", "Question": "This field represents the question to be asked.", "QuestionID": 22, "Scenario": "something needed to expand on the question asked.", "Answer": "correct answer for question." } ]
当前环境:Windows、VSCode、React 18.3.1、npm 10.8.0、npx 10.8.0
现有Question.js代码无法运行:
import React from 'react'; function GetQuestion() { const fetchData = async () => { const request_url = 'http://127.0.0.1:5000/exam/question'; const request_json= '{"exam_id": '+{exam_id}+', "question_id": '+{question_id}+'}'; const request={request_url} + '?' + {request_json}; const response = await fetch(request); const response_data = await response.json(); setData(response_data); }; return fetchData() } export default GetQuestion;
问题修复与React最佳实践
一、现有代码的核心错误
- 参数未传入:
exam_id和question_id未作为函数参数传入,直接引用会引发未定义错误 - GET参数格式错误:GET请求不能直接拼接JSON字符串到URL,需转为标准查询参数(如
?exam_id=1&question_id=22) - 状态缺失:
setData未对应声明useState变量 - 逻辑循环:组件渲染时直接返回
fetchData()会触发无限调用接口
二、React中的标准实现方案
1. 独立封装API请求模块
将API逻辑与组件解耦,放在单独的api/questions.js文件,方便多组件复用:
// api/questions.js const BASE_URL = process.env.REACT_APP_API_URL || 'http://127.0.0.1:5000'; export const fetchQuestion = async (examId, questionId) => { const url = new URL(`${BASE_URL}/exam/question`); // 添加标准查询参数 url.searchParams.append('exam_id', examId); url.searchParams.append('question_id', questionId); const response = await fetch(url.toString()); // 处理HTTP错误 if (!response.ok) { throw new Error(`请求失败: ${response.statusText}`); } return await response.json(); };
2. 封装自定义Hook处理React状态
在hooks/useQuestion.js中封装加载、错误、数据状态,简化组件逻辑:
// hooks/useQuestion.js import { useState, useEffect } from 'react'; import { fetchQuestion } from '../api/questions'; export const useQuestion = (examId, questionId) => { const [data, setData] = useState(null); const [loading, setLoading] = useState(false); const [error, setError] = useState(null); const loadQuestion = async () => { setLoading(true); setError(null); try { const result = await fetchQuestion(examId, questionId); setData(result); } catch (err) { setError(err.message); } finally { setLoading(false); } }; // 参数变化时自动重新请求 useEffect(() => { if (examId && questionId) { loadQuestion(); } }, [examId, questionId]); return { data, loading, error, refetch: loadQuestion }; };
3. 在Home组件中使用自定义Hook
// Home.js import { useQuestion } from './hooks/useQuestion'; function Home() { // 根据业务逻辑动态传入参数 const { data, loading, error, refetch } = useQuestion(1, 22); if (loading) return <div>加载中...</div>; if (error) return <div>出错了: {error}</div>; if (!data) return <div>无数据</div>; const question = data[0]; return ( <div className="question-container"> <h3>{question.Question}</h3> <p className="scenario">{question.Scenario}</p> <ul className="choices"> <li>{question.Choice_1}</li> <li>{question.Choice_2}</li> <li>{question.Choice_3}</li> <li>{question.Choice_4}</li> <li>{question.Choice_5}</li> </ul> <button onClick={refetch}>重新加载</button> </div> ); } export default Home;
三、额外最佳实践建议
- 取消请求:组件卸载时用
AbortController取消未完成的请求,避免内存泄漏 - 参数校验:在API函数中添加参数合法性检查,比如验证
examId和questionId为有效数字 - 环境变量:用
.env文件存储API地址(如REACT_APP_API_URL),方便不同环境切换 - 全局错误处理:可封装全局的错误捕获逻辑,统一处理API请求异常
四、关于GET请求传JSON的说明
GET请求优先使用标准查询参数格式,若后端强制要求传JSON,可将JSON编码后作为单个查询参数值:
const params = encodeURIComponent(JSON.stringify({ exam_id: 1, question_id: 22 })); const url = `${BASE_URL}/exam/question?data=${params}`;
但这种方式不符合HTTP规范,不推荐使用。
内容的提问来源于stack exchange,提问作者Joseph McTigue
相关产品推荐
相关产品推荐

