React多餐段搜索框如何实现搜索结果仅在对应区域独立渲染
问题根因
- 你在早餐搜索触发的接口请求回调中,同时给
data(早餐结果集)和data2(午餐结果集)赋值了相同的返回数据,所以早餐的搜索结果会同步出现在午餐区域 - 仅配置了监听早餐搜索词
result的副作用,没有为午餐搜索词result2配置对应的搜索逻辑,午餐输入内容不会触发独立请求 - 额外冗余问题:午餐的
label标签上错误绑定了onChange事件,属于无效代码
修复后代码
import React, {useState, useEffect} from 'react' import axios from 'axios' function DietForm() { // 早餐相关状态 const [breakfastQuery, setBreakfastQuery] = useState('') const [breakfastData, setBreakfastData] = useState([]) // 午餐相关状态 const [lunchQuery, setLunchQuery] = useState('') const [lunchData, setLunchData] = useState([]) // 晚餐相关状态 const [dinnerQuery, setDinnerQuery] = useState('') const [dinnerData, setDinnerData] = useState([]) // 零食相关状态 const [snackQuery, setSnackQuery] = useState('') const [snackData, setSnackData] = useState([]) const [loading, setLoading] = useState(false) const [message, setMessage] = useState('') // 封装通用请求方法,避免重复代码 const fetchFoodList = async (query, setData) => { if (!query.trim()) { setData([]) return } const options = { method: 'GET', url: 'https://edamam-food-and-grocery-database.p.rapidapi.com/parser', params: {ingr: query}, headers: { 'x-rapidapi-host': 'edamam-food-and-grocery-database.p.rapidapi.com', 'x-rapidapi-key': '6bc4948226msh1716c54bf80ad8dp1c8c12jsnac7a17a9e0a6' } }; try { const res = await axios.request(options) setData(res.data) } catch (err) { console.error(err) } } // 早餐搜索副作用 useEffect(() => { fetchFoodList(breakfastQuery, setBreakfastData) }, [breakfastQuery]) // 午餐搜索副作用 useEffect(() => { fetchFoodList(lunchQuery, setLunchData) }, [lunchQuery]) // 晚餐搜索副作用 useEffect(() => { fetchFoodList(dinnerQuery, setDinnerData) }, [dinnerQuery]) // 零食搜索副作用 useEffect(() => { fetchFoodList(snackQuery, setSnackData) }, [snackQuery]) return ( <div> <form class="w-full max-w-lg"> {/* 早餐区域 */} <div class="flex flex-wrap -mx-3 mb-6"> <div class="w-full md:w-1/2 px-3 mb-6 md:mb-0"> <label class="block uppercase tracking-wide text-gray-700 text-xs font-bold mb-2" for="breakfast-input"> Breakfast </label> <input value={breakfastQuery} class="appearance-none block w-full bg-gray-200 text-gray-700 border border-red-500 rounded py-3 px-4 mb-3 leading-tight focus:outline-none focus:bg-white" id="breakfast-input" type="text" onChange={(e) => setBreakfastQuery(e.target.value)} placeholder="Search" /> {breakfastData?.hints?.map((item) => ( <div key={item.food.foodId || item.id}> {item.food.label} <button>Add</button> </div> )) || 'No results found'} </div> </div> {/* 午餐区域 */} <div class="flex flex-wrap -mx-3 mb-6"> <div class="w-full md:w-1/2 px-3"> <label class="block uppercase tracking-wide text-gray-700 text-xs font-bold mb-2" for="lunch-input"> Lunch </label> <input value={lunchQuery} class="appearance-none block w-full bg-gray-200 text-gray-700 border border-gray-200 rounded py-3 px-4 leading-tight focus:outline-none focus:bg-white focus:border-gray-500" id="lunch-input" type="text" onChange={(e) => setLunchQuery(e.target.value)} placeholder="Search" /> {lunchData?.hints?.map((item) => ( <div key={item.food.foodId || item.id}> {item.food.label} <button>Add</button> </div> )) || 'No results found'} </div> </div> {/* 晚餐区域 */} <div class="flex flex-wrap -mx-3 mb-2"> <div class="w-full md:w-1/2 px-3"> <label class="block uppercase tracking-wide text-gray-700 text-xs font-bold mb-2" for="dinner-input"> Dinner </label> <input value={dinnerQuery} class="appearance-none block w-full bg-gray-200 text-gray-700 border border-gray-200 rounded py-3 px-4 leading-tight focus:outline-none focus:bg-white focus:border-gray-500" id="dinner-input" type="text" onChange={(e) => setDinnerQuery(e.target.value)} placeholder="Search" /> {dinnerData?.hints?.map((item) => ( <div key={item.food.foodId || item.id}> {item.food.label} <button>Add</button> </div> )) || 'No results found'} </div> </div> {/* 零食区域 */} <div class="flex flex-wrap -mx-3 mb-2"> <div class="w-full md:w-1/2 px-3"> <label class="block uppercase tracking-wide text-gray-700 text-xs font-bold mb-2" for="snack-input"> Snack </label> <input value={snackQuery} class="appearance-none block w-full bg-gray-200 text-gray-700 border border-gray-200 rounded py-3 px-4 leading-tight focus:outline-none focus:bg-white focus:border-gray-500" id="snack-input" type="text" onChange={(e) => setSnackQuery(e.target.value)} placeholder="Search" /> {snackData?.hints?.map((item) => ( <div key={item.food.foodId || item.id}> {item.food.label} <button>Add</button> </div> )) || 'No results found'} </div> </div> </form> </div> ) } export default DietForm
优化建议
如果后续需要维护更多搜索区域,可把单个餐段的搜索逻辑封装为独立的MealSearch组件,每个组件内部维护自己的搜索词、结果集和请求逻辑,父组件仅需要传入餐段名称即可,可大幅减少重复代码。
内容的提问来源于stack exchange,提问作者Chen
相关产品推荐
相关产品推荐

