React蛋糕列表搜索过滤表单失效报错问题修复
React 蛋糕搜索表单报错修复
问题根因
共5处代码错误,直接导致搜索失效、运行报错:
- 自定义Hook调用语法错误:
useGlobalContext是封装的函数,在SearchForm和CakeList组件中调用时都没有加()执行,直接从函数对象上解构状态,拿到的所有值都是undefined,是触发运行时报错的核心原因 - 状态命名不匹配:Context中存储过滤结果的状态名是
filteredData,CakeList组件中错误写成了filteredResults,无法读取到正确的过滤后列表 - 搜索词状态未更新:输入框触发onChange时传入了输入值,但
searchCakes函数没有接收参数,也没有调用setSearchTerm同步更新搜索词状态,导致searchTerm始终为空字符串 - 过滤列表无初始值:接口拉取到全量蛋糕数据后,没有给
filteredData赋初始值,首次加载时过滤列表为空 - 表单默认行为未拦截:搜索form没有绑定提交事件,输入时按回车会触发页面默认刷新
修复后代码
context.js
import React, { useState, useContext, useEffect } from "react"; const url = "https://cakeaddicts-api.herokuapp.com/cakes"; const AppContext = React.createContext(); const AppProvider = ({ children }) => { const [loading, setLoading] = useState(false); const [searchTerm, setSearchTerm] = useState(""); const [cakes, setCakes] = useState([]); const [filteredData, setFilteredData] = useState([]); const fetchCakes = async () => { setLoading(true); try { const response = await fetch(url); const cakes = await response.json(); if (cakes) { const newCakes = cakes.map((cake) => { const { id, image, cake_name, category, type, ingredients, instructions, } = cake; return { id, image, cake_name, category, type, ingredients, instructions, }; }); setCakes(newCakes); // 初始化过滤列表为全量蛋糕数据 setFilteredData(newCakes); } else { setCakes([]); setFilteredData([]); } setLoading(false); } catch (error) { console.log(error); setLoading(false); } }; useEffect(() => { fetchCakes(); }, []); return ( <AppContext.Provider value={{ loading, cakes, setSearchTerm, searchTerm, filteredData, setFilteredData, }} > {children} </AppContext.Provider> ); }; export const useGlobalContext = () => { return useContext(AppContext); }; export { AppContext, AppProvider };
SearchForm.js
import React from "react"; import { useGlobalContext } from "../context"; const SearchForm = () => { // 修复:Hook调用加括号执行 const { cakes, setSearchTerm, setFilteredData } = useGlobalContext(); // 修复:接收输入值参数 const searchCakes = (value) => { // 同步更新搜索词状态 setSearchTerm(value); const keyword = value.toLowerCase().trim(); if (keyword) { const filtered = cakes.filter((item) => { // 仅按蛋糕名搜索,需要全字段匹配可替换为原Object.values逻辑 return item.cake_name.toLowerCase().includes(keyword); }); setFilteredData(filtered); } else { setFilteredData(cakes); } }; return ( <section className="section search"> {/* 修复:阻止表单默认提交刷新行为 */} <form className="search-form" onSubmit={(e) => e.preventDefault()}> <div className="form-control"> <label htmlFor="name">Search Your Favourite Cake</label> <input type="text" id="name" onChange={(e) => searchCakes(e.target.value)} /> </div> </form> </section> ); }; export default SearchForm;
注:原文件中未使用的CakeList导入已删除
CakeList.js
import React from "react"; import Cake from "./Cake"; import Loading from "./Loading"; import { useGlobalContext } from "../context.js"; const CakeList = () => { // 修复:Hook调用加括号,修正过滤列表状态名 const { cakes, loading, searchTerm, filteredData } = useGlobalContext(); if (loading) { return <Loading />; } return ( <section className="section"> <h2 className="section-title">Cakes</h2> <div className="cakes-center"> {searchTerm.length > 0 ? filteredData.map((cake) => { return <Cake key={cake.id} {...cake} />; }) : cakes.map((item) => { return <Cake key={item.id} {...item} />; })} </div> </section> ); }; export default CakeList;
注:搜索触发阈值从原长度>1调整为>0,输入单个字符即可触发过滤,可根据业务需求自行调整
内容的提问来源于stack exchange,提问作者Kay
相关产品推荐
相关产品推荐

