React函数式组件无法通过子组件回调更新父组件state问题求助
问题解决说明
核心原因
React 中 useState 的状态更新为异步批量执行逻辑,同一个函数执行上下文内调用状态更新方法后,当前闭包中的状态变量仍为本次渲染初始化时的旧值,更新后的值要到下一次组件渲染时才能拿到。你打印结果中childData是最新值、API是旧值的表现,就是该特性的直接体现。
代码中存在的其他问题
- useEffect 依赖配置错误:当前依赖为
characterData.length,会导致死循环:请求返回后更新characterData触发长度变化,又会触发 useEffect 重新发请求,无限重复执行 makeNetworkRequest内部冗余调用setAPI,额外增加状态更新不可控性
推荐修正方案
这里提供两种符合React开发规范的实现方式:
方案1:直接传递新地址发起请求(命令式写法)
import React, { useEffect, useState } from "react"; import Character from "../component/Character"; import Filter from "../component/Filter"; import Pagination from "../component/Pagination"; import axios from "axios"; import "./Home.css"; const Home = (props) => { const [API, setAPI] = useState(`https://someapi.com/api/character/?gender=&status=&name=`); const [characterData, setCharacterData] = useState([]); const [pagination, setPagination] = useState(0); const makeNetworkRequest = (data) => { setAPI(data); setTimeout(() => { axios.get(data).then(resp => { setPagination(resp.data.info) setCharacterData(resp.data.results) }) }, 1000) } const handleFormCallBack = (childData) => { // 直接传递新的地址发起请求,不依赖当前状态值 makeNetworkRequest(childData); } // 仅组件挂载时执行一次初始请求 useEffect(() => { makeNetworkRequest(API) }, []); const mappedCharacters = characterData.length > 0 ? characterData.map((character) => <Character key={character.id} id={character.id} alive={character.status} gender={character.gender} name={character.name} image={character.image} />) : <h4>Loading...</h4> return ( <div className="home-container"> <h3>Home</h3> <Filter parentCallBack={handleFormCallBack} /> <div className="characters-container"> {mappedCharacters} </div> </div> ) } export default Home;
方案2:依赖状态自动触发请求(声明式写法,更推荐)
import React, { useEffect, useState } from "react"; import Character from "../component/Character"; import Filter from "../component/Filter"; import Pagination from "../component/Pagination"; import axios from "axios"; import "./Home.css"; const Home = (props) => { const [API, setAPI] = useState(`https://someapi.com/api/character/?gender=&status=&name=`); const [characterData, setCharacterData] = useState([]); const [pagination, setPagination] = useState(0); const makeNetworkRequest = (data) => { setTimeout(() => { axios.get(data).then(resp => { setPagination(resp.data.info) setCharacterData(resp.data.results) }) }, 1000) } const handleFormCallBack = (childData) => { // 仅更新API状态 setAPI(childData); } // 监听API变化,自动发起新请求 useEffect(() => { makeNetworkRequest(API) }, [API]); const mappedCharacters = characterData.length > 0 ? characterData.map((character) => <Character key={character.id} id={character.id} alive={character.status} gender={character.gender} name={character.name} image={character.image} />) : <h4>Loading...</h4> return ( <div className="home-container"> <h3>Home</h3> <Filter parentCallBack={handleFormCallBack} /> <div className="characters-container"> {mappedCharacters} </div> </div> ) } export default Home;
内容的提问来源于stack exchange,提问作者Sarbraj Dulai
相关产品推荐
相关产品推荐

