You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React(Ts)多复选框筛选失效,调用Edamam API报400错误

Edamam API多筛选条件触发400错误问题

我在用Edamam API获取食谱,单个筛选条件能正常工作,但选择多个时会触发Axios 400错误。

错误信息

react_devtools_backend_compact.js:13851 Error fetching recipes:
AxiosError {message: 'Request failed with status code 400', name: 'AxiosError', code: 'ERR_BAD_REQUEST', config: {…}, request: XMLHttpRequest, …}
code:
"ERR_BAD_REQUEST"
config:
{transitional: {…}, adapter: Array(3), transformRequest: Array(1),
transformResponse: Array(1), timeout: 0, …}
message:
"Request failed with status code 400"
name:
"AxiosError"
request:
XMLHttpRequest {onreadystatechange: null, readyState: 4, timeout: 0,
withCredentials: false, upload: XMLHttpRequestUpload, …}
response:
{data: {…}, status: 400, statusText: '', headers: AxiosHeaders, config: {…}, …}

相关代码

components/SearchBar.tsx

"use client"
import PrimaryButton from '@/components/PrimaryButton';
import { Box, Button, Card, CardContent, TextField, Typography } from '@mui/material';
import React, { useState } from 'react';

interface SearchBarProps {
  onSearch: (query: string , filters: { diet: string[] }) => void;
}

const SearchBar: React.FC<SearchBarProps> = ({ onSearch }) => {
  const [query, setQuery] = useState('');
  const [error, setError] = useState('');
  
  // Filter state
  const [dietFilter, setDietFilter] = useState<string[]>([]);

  const handleSubmit = (e: React.FormEvent<HTMLFormElement>) => {
    e.preventDefault();

    if (!query.trim()) {
      setError('Search query must not be null or empty');
      return;
    }

    setError(''); // Clear error if query is valid
    console.log("Search query:", query); // Debug statement
   
    onSearch(query, { diet: dietFilter });
  };

  const handleDietChange = (event: React.ChangeEvent<HTMLInputElement>) => {
    const { value, checked } = event.target;
    setDietFilter((prevDietFilter) =>
      checked ? [...prevDietFilter, value] : prevDietFilter.filter((diet) => diet !== value)
    );
  };
  
  return ( 
    <>
    <Box display="flex" justifyContent="center" alignItems="center" minHeight="80vh">
      <Card sx={{ maxWidth: 500, width: '100%', p: 2 }}>
        <CardContent>
          <Typography variant="h6" component="h6" gutterBottom>
              Find the recipe
          </Typography>
              <Box  mt={2} display="flex" alignItems="center">
                <form onSubmit={handleSubmit}>                 
                <TextField
                type="text"
                value={query}
                onChange={(e) => setQuery(e.target.value)}
                placeholder="Search for recipes"
                variant="outlined"
                fullWidth 
                sx={{ mb: 2 }}
                error={Boolean(error)} // Show error state
                helperText={error} // Display the error message
              />
              <Box mb={2}>
              <Typography variant="subtitle1">Diet</Typography>
              <label>
                <input type="checkbox" value="low-carb" onChange={handleDietChange} /> Low-Carb
              </label>
              <label style={{ marginLeft: '10px' }}>
                <input type="checkbox" value="high-protein" onChange={handleDietChange} /> High-Protein
              </label>
            </Box>

                  <PrimaryButton type="submit"  variant="contained">Search</PrimaryButton>
           
                </form>             
              </Box>
              </CardContent>
              </Card>
     
         </Box>
    </>
  );
};

export default SearchBar;

api.tsx

const API_URL = 'https://api.edamam.com/api/recipes/v2';
const APP_ID = process.env.NEXT_PUBLIC_APP_ID;
const APP_KEY = process.env.NEXT_PUBLIC_APP_KEY;

export const fetchRecipes = async (query: string, filters: FetchRecipesFilters = {}): Promise<Recipe[]> => {
  if (!query) {
    throw new Error('Search query must not be null or empty');
  }

  try {
    // Debug: Log the query and filters
    console.log('Query:', query);
    console.log('Filters:', filters);

    const params: Record<string, string> = {
      type: 'public',
      q: query,
      app_id: APP_ID!,
      app_key: APP_KEY!,
    };

    // If diet filters are provided, add them to the params
    if (filters.diet && filters.diet.length > 0) {
      params.diet = filters.diet.join(','); // Join filters with a comma
    }

     // Debug: Log the params being sent to the API
     console.log('Request Params:', params);

     const response = await axios.get<ApiResponse>(API_URL, {
       params,
     });
 
    if (!response.data.hits) {
      throw new Error('No recipes found');
    }

    return response.data.hits.map((hit) => hit.recipe);
  } catch (error) {
    console.error('Error fetching recipes:', error);
    
    return [];
  }
};

SearchContent.tsx

interface RecipeProp {
  uri: string;
  label: string;
  image: string;
  images: Images;
  ingredientLines: string[];
  }
  
  export default function RecipeSearchContent() {
    const [recipes, setRecipes] = React.useState<RecipeProp[]>([]);
    const [isMounted, setIsMounted] = useState(true);

    useEffect(() => {
      setIsMounted(true);
  
      return () => {
        setIsMounted(false);
      };
    }, []);
  
    const handleSearch = useCallback(async (query: string ,  filters: FetchRecipesFilters) => {
      try {
        // Fetch recipes from the API
        const results: RecipeProp[] = await fetchRecipes(query, filters);
  
        // If the component is still mounted, update the state
        if (isMounted) {
          setRecipes(results);
        }
      } catch (error) {
        console.error("Error fetching recipes:", error);
      }
    }, [isMounted]);
  
    return (
      <Container>
        <SearchBar onSearch={handleSearch} />
        <RecipeListContent recipes={recipes} />
      </Container>
    );
  }

问题原因及修复

Edamam API的多diet筛选条件不支持逗号拼接的单参数格式,而是需要重复传递diet参数(每个筛选条件对应一个diet=xxx)。当前代码将多个diet值用逗号拼接成单个参数,不符合API要求,导致400错误。

修改api.tsx中的参数处理逻辑:

  1. 调整params的类型,允许数组值
  2. 直接将diet数组赋值给params.diet,axios会自动转换为多个同名参数

修改后的关键代码:

// 调整params类型,支持数组值
const params: Record<string, string | string[]> = {
  type: 'public',
  q: query,
  app_id: APP_ID!,
  app_key: APP_KEY!,
};

// 处理diet筛选条件
if (filters.diet && filters.diet.length > 0) {
  params.diet = filters.diet; // 直接传递数组,axios自动生成多个diet参数
}

修改后,请求参数会变为diet=low-carb&diet=high-protein,符合Edamam API的要求,即可解决400错误。

内容的提问来源于stack exchange,提问作者user17449555

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.19 14:50:06