
在react中构建交互式表单,并将其与后端api进行数据交互是常见的开发任务。然而,开发者常会遇到一些问题,例如表单提交后页面意外刷新、api请求未按预期触发或数据未正确更新。这些问题往往源于对react生命周期、钩子(hooks)使用规则以及dom事件处理机制的误解。
考虑以下场景,一个搜索框需要根据用户输入触发API请求,并显示结果。原始代码可能存在以下几个核心问题:
原始代码示例(存在问题的版本):
import React, {useState, useEffect} from "react"
import "../../styles/components.css"
import './Recipes.css'
const key = 'API_KEY';
export default function Recipes() {
const [posts, setPosts] = useState([]);
const [searchInput, setSearchInput] = useState("");
const recipesDisplay = posts?.map((response, i) => (
<div key={response.id} className="list-group-item">
<img src={response.image_url} alt={response.title} />
<h3>{response.title}</h3>
<p>By: {response.publisher}</p>
</div>
));
const handleChange = (e) => {
e.preventDefault(); // 此处阻止的是输入框的默认行为,而非表单提交
setSearchInput(e.target.value);
};
// 错误:useEffect 不应放在嵌套函数中
const ShowPosts = () => {
useEffect( () => {
async function fetchData() {
try {
const response = await fetch(`https://forkify-api.herokuapp.com/api/v2/recipes?search=${searchInput}&key=${key}`);
if (response.ok) {
const jsonResponse = await response.json();
console.log(searchInput);
setPosts(jsonResponse.data.recipes);
console.log(jsonResponse);
}
} catch (err) {
console.error("Failed to fetch recipes:", err); // 使用 console.error
}
}
fetchData();
}, []); // 依赖数组为空,意味着只在组件挂载时运行一次,不会响应 searchInput 变化
}
return (
<div className="main">
<h1>Recipes</h1>
<form> {/* 表单提交的默认行为是刷新页面 */}
<input
type="search"
placeholder="Search here"
onChange={handleChange}
value={searchInput}
/>
<button onClick={handleChange}>Submit</button> {/* 按钮点击事件绑定错误 */}
</form>
{ShowPosts()} {/* 错误:在渲染函数中调用一个包含 useEffect 的函数 */}
{recipesDisplay}
</div>
)
}要解决上述问题,我们需要遵循React Hooks的规则,并正确处理DOM事件。
useEffect是用于处理副作用的钩子,如数据获取、订阅或手动更改DOM。它必须在函数式组件的顶层调用。其第二个参数是一个依赖项数组,只有当数组中的值发生变化时,useEffect的回调函数才会重新执行。
将API请求逻辑直接移入Recipes组件的顶层useEffect中,并将其依赖项设置为[searchInput],确保当searchInput发生变化时,API请求会被重新触发。
为了防止表单提交时的页面刷新,我们需要在<form>元素上使用onSubmit事件处理器,并在事件处理函数中调用event.preventDefault()。同时,搜索按钮应触发这个提交事件,而不是handleChange。
输入框的onChange事件负责实时更新searchInput状态,而表单的onSubmit事件负责在用户点击提交按钮或按回车键时触发API请求。
移除不必要的嵌套函数ShowPosts,将逻辑扁平化,使组件更易于理解和维护。
import React, { useState, useEffect, useCallback } from "react";
import "../../styles/components.css";
import './Recipes.css';
const key = 'YOUR_API_KEY'; // 请替换为您的实际API Key
export default function Recipes() {
const [posts, setPosts] = useState([]);
const [searchInput, setSearchInput] = useState("");
const [searchTerm, setSearchTerm] = useState(""); // 新增一个状态用于触发API请求
// 处理输入框变化的函数
const handleInputChange = (e) => {
setSearchInput(e.target.value);
};
// 处理表单提交的函数
const handleFormSubmit = (e) => {
e.preventDefault(); // 阻止表单默认提交行为,防止页面刷新
setSearchTerm(searchInput); // 将当前输入值设置为触发API请求的searchTerm
};
// 使用 useEffect 来触发 API 请求
// 依赖项数组中包含 searchTerm,只有当 searchTerm 改变时,effect 才会重新运行
useEffect(() => {
if (!searchTerm) {
// 如果 searchTerm 为空,则不执行 API 请求,例如在组件初次加载时
// 或者可以设置为加载默认数据
return;
}
async function fetchData() {
try {
const response = await fetch(`https://forkify-api.herokuapp.com/api/v2/recipes?search=${searchTerm}&key=${key}`);
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const jsonResponse = await response.json();
console.log("Fetched search term:", searchTerm);
console.log("API Response:", jsonResponse);
setPosts(jsonResponse.data.recipes || []); // 确保即使没有结果也设置为[]
} catch (err) {
console.error("Failed to fetch recipes:", err);
setPosts([]); // 请求失败时清空数据
}
}
fetchData();
}, [searchTerm]); // 依赖 searchTerm,当 searchTerm 变化时重新运行 effect
// 渲染食谱列表
const recipesDisplay = posts.length > 0 ? (
posts.map((response) => (
<div key={response.id} className="list-group-item">
<img src={response.image_url} alt={response.title} />
<h3>{response.title}</h3>
<p>By: {response.publisher}</p>
</div>
))
) : (
<p>No recipes found. Try searching for something else!</p>
);
return (
<div className="main">
<h1>Recipes</h1>
<form onSubmit={handleFormSubmit}> {/* 绑定表单提交事件 */}
<input
type="search"
placeholder="Search here"
onChange={handleInputChange} // 绑定输入框变化事件
value={searchInput} // 受控组件
/>
<button type="submit">Submit</button> {/* 按钮类型为 submit */}
</form>
<div className="recipes-list">
{recipesDisplay}
</div>
</div>
);
}代码改进说明:
通过遵循这些最佳实践,您可以构建出响应迅速、功能稳定且易于维护的React表单和数据获取组件。
以上就是React表单输入与API请求:解决数据不更新和页面刷新问题的详细内容,更多请关注php中文网其它相关文章!
每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号