React卡片中按需循环渲染食材的实现方法
如何在React食谱卡片中循环渲染指定数量的食材
核心思路:替换硬编码食材列表为动态循环
你的代码目前手动写了14个Card.Text展示食材,既冗余又无法灵活控制数量。可以通过以下几步实现按需展示:
1. 编写工具函数提取结构化食材数据
API返回的食材是strIngredient1到strIngredient20这类零散字段,先把它们转换成数组,同时过滤空值(很多食谱的后续食材字段为空):
const getIngredients = (meal) => { const ingredients = []; // 遍历API支持的最多20种食材 for (let i = 1; i <= 20; i++) { const ingredient = meal[`strIngredient${i}`]; const measure = meal[`strMeasure${i}`]; // 只保留有实际内容的食材 if (ingredient && ingredient.trim()) { ingredients.push({ name: ingredient, measure }); } } return ingredients; };
2. 给每个食谱设置自定义显示数量
你需要每张卡片展示不同数量的食材,比如卡片1显示5种、卡片2显示10种,可以在获取API数据后给每个食谱添加自定义字段:
.then((json) => { const processedMeals = json.meals?.map((meal, index) => ({ ...meal, // 这里用索引奇偶区分,你也可以改成自己的规则(比如从后端获取、手动配置) displayCount: index % 2 === 0 ? 5 : 10 })) || []; setData(processedMeals); });
3. 用循环渲染指定数量的食材
把原来硬编码的Card.Text替换成循环,只渲染设定数量的食材:
<div id='ing'> {/* 先获取食材数组,再截取前N个(N为自定义的displayCount) */} {getIngredients(res).slice(0, res.displayCount).map((ing, idx) => ( <Card.Text key={idx}>{ing.name}-{ing.measure}</Card.Text> ))} </div>
完整修改后的组件代码
function LiveData() { const [mydata, setData] = useState([]); // 提取食材的工具函数 const getIngredients = (meal) => { const ingredients = []; for (let i = 1; i <= 20; i++) { const ingredient = meal[`strIngredient${i}`]; const measure = meal[`strMeasure${i}`]; if (ingredient && ingredient.trim()) { ingredients.push({ name: ingredient, measure }); } } return ingredients; }; const api = () => { // 修正原代码fetch的错误:第二个参数传错,已移除 fetch("https://www.themealdb.com/api/json/v1/1/search.php?s=") .then((response) => response.json()) .then((json) => { // 给每个食谱添加自定义食材显示数量 const processedMeals = json.meals?.map((meal, index) => ({ ...meal, displayCount: index % 2 === 0 ? 5 : 10 })) || []; setData(processedMeals); }); }; useEffect(() => { api(); const interval = setInterval(() => { api(); }, 20000); return () => clearInterval(interval); }, []); return ( <> <Container fluid> <Row xs={1} md={3} className="g-4"> {mydata.map((res, idx) => ( {/* React列表渲染必须添加唯一key */} <Col key={idx} className="container-fluid mt-4"> <Card> <Card.Img variant="top" src={res.strMealThumb} height="340px" width="500px" /> <Card.Body> <Card.Title>{res.strMeal}</Card.Title> <Card.Text>{res.strArea}</Card.Text> <b>Ingredients: </b> <div id='ing'> {getIngredients(res).slice(0, res.displayCount).map((ing, ingIdx) => ( <Card.Text key={ingIdx}>{ing.name}-{ing.measure}</Card.Text> ))} </div> <Card.Link> <a href={res.strYoutube} target="_blank" rel="noopener noreferrer" // 符合安全规范,防止钓鱼攻击 > YouTube Video for {res.strMeal} </a> </Card.Link> </Card.Body> </Card> </Col> ))} </Row> </Container> </> ); }
额外提示
- 原代码中
fetch的第二个参数是错误的,fetch的第二个参数是请求配置(如POST的body),不是查询参数,已修正 - 给所有列表项添加了
key属性,避免React渲染警告 - 如果需要动态调整显示数量(比如添加"显示更多"按钮),可以给每个卡片单独维护状态,点击时修改
displayCount的值
内容的提问来源于stack exchange,提问作者Priya Prajapati
相关产品推荐
相关产品推荐

