React开发中如何将RecipeList组件的setRecipeList传递到App.js使用
React遵循单向数据流,子组件内部定义的state默认无法直接传递给父组件调用,你可以选择以下两种方案实现需求,更推荐方案一(状态提升),符合React官方设计规范。
方案一:状态提升(推荐)
把食谱列表的状态从子组件RecipeList提升到父组件App中统一管理,父组件拿到接口返回数据后直接更新状态,再将状态作为props传递给RecipeList渲染即可。
修改后的App.js代码:
import React, { useState } from "react"; import Axios from "axios"; import Header from "./Components/Header"; import RecipeList from "./Components/RecipeList"; // 注意替换为你自己的APP_ID和APP_KEY const APP_ID = "你的应用ID"; const APP_KEY = "你的应用密钥"; function App() { const [timeoutId, setTimeoutId] = useState(); // 把食谱列表状态提升到App组件 const [recipeList, setRecipeList] = useState([]); const fetchRecipe = async (searchString) => { const response = await Axios.get( `https://api.edamam.com/search?q=${searchString}&app_id=${APP_ID}&app_key=${APP_KEY}` ); // 接口返回后直接更新状态 setRecipeList(response.data.hits); }; const onTextChangeHandler = (e) => { //防抖逻辑 clearTimeout(timeoutId); const timeout = setTimeout(() => fetchRecipe(e.target.value), 500); setTimeoutId(timeout); }; return ( <> <Header onTextChange = {onTextChangeHandler} /> {/* 将食谱列表作为props传递给子组件 */} <RecipeList list={recipeList}/> </> ); } export default App;
修改后的RecipeList.js代码:
import React from "react"; import Recipe from "./Recipe"; import styles from "./RecipeList.module.css"; // 直接接收父组件传递的列表数据 const RecipeList = (props) => { return ( <div className={styles.recipe_list}> {props.list?.length > 0 && props.list.map((recipeObj, index) => (<Recipe key={index} recipeObj={recipeObj.recipe} />))} </div> ); }; export default RecipeList;
注意:edamam接口返回的每条食谱数据存放在hits数组元素的recipe字段下,渲染时需要对应取值,同时给map遍历的子元素加key属性避免React报错。
方案二:通过ref暴露子组件方法(仅适合不需要频繁共享状态的场景)
如果你不想调整状态位置,可以通过forwardRef+useImperativeHandle把setRecipeList方法暴露给父组件调用:
修改后的RecipeList.js代码:
import React, { useState, useImperativeHandle, forwardRef } from "react"; import Recipe from "./Recipe"; import styles from "./RecipeList.module.css"; // 用forwardRef包裹组件接收ref参数 const RecipeList = forwardRef((props, ref) => { const [recipeList, setRecipeList] = useState([]); // 暴露方法给父组件的ref调用 useImperativeHandle(ref, () => ({ updateList: (newList) => setRecipeList(newList) })) return ( <div className={styles.recipe_list}> {recipeList.length > 0 && recipeList.map((recipeObj, index) => (<Recipe key={index} recipeObj={recipeObj.recipe} />))} </div> ); }); export default RecipeList;
修改后的App.js代码:
import React, { useState, useRef } from "react"; import Axios from "axios"; import Header from "./Components/Header"; import RecipeList from "./Components/RecipeList"; const APP_ID = "你的应用ID"; const APP_KEY = "你的应用密钥"; function App() { const [timeoutId, setTimeoutId] = useState(); // 创建ref绑定到RecipeList组件 const recipeListRef = useRef(); const fetchRecipe = async (searchString) => { const response = await Axios.get( `https://api.edamam.com/search?q=${searchString}&app_id=${APP_ID}&app_key=${APP_KEY}` ); // 调用子组件暴露的方法更新列表 recipeListRef.current?.updateList(response.data.hits); }; const onTextChangeHandler = (e) => { clearTimeout(timeoutId); const timeout = setTimeout(() => fetchRecipe(e.target.value), 500); setTimeoutId(timeout); }; return ( <> <Header onTextChange = {onTextChangeHandler} /> {/* 绑定ref */} <RecipeList ref={recipeListRef}/> </> ); } export default App;
内容的提问来源于stack exchange,提问作者M. R
相关产品推荐
相关产品推荐

