React结合Context更新state仅在第二次点击后生效问题求助
问题根源
- React函数组件的
useState返回的状态更新函数不支持第二个回调参数,这是类组件setState的专属特性,你写的setDays(newDays, getNewData())本身是无效写法,而且你直接执行了getNewData()而非传入函数引用。 - React的状态更新是异步批量处理的,调用
setDays后,当前函数作用域内的days变量不会立刻更新,此时直接调用getNewData,传入getData的是更新前的旧days值,所以第一次请求拿到的是旧数据,第二次点击时days已经是上一次更新后的值,才会请求到对应的数据,看起来就需要点击两次才能生效。 - 函数声明顺序错误:你把
getNewData、daysChangeHandler定义在useState声明之前,函数闭包捕获的是初始的days默认值,永远拿不到更新后的状态,这也是你之前加的useEffect不生效的核心原因。
修复方案
直接替换DataContextProvider的代码即可:
import { createContext, useState, useEffect } from 'react' const DataContext = createContext({ days: 720, data: { timestamp: [], price: [], short_ma: [], long_ma: [], money: [], action: [] }, daysChangeHandler: (newDays) => {} }) export default DataContext export const DataContextProvider = (props) => { // 1. 先声明状态,再定义依赖状态的函数,避免闭包捕获旧值 const [days, setDays] = useState(720) const [data, setData] = useState({ timestamp: [], price: [], short_ma: [], long_ma: [], money: [], action: [] }) // 2. 请求方法接收目标天数作为入参,不依赖当前作用域的状态变量 const getNewData = async (targetDays) => { const response = await getData(targetDays) setData(response) console.log('NEW DATA') } const daysChangeHandler = (newDays) => { setDays(newDays) } // 3. 监听days变化,状态更新后自动用最新的天数请求数据 useEffect(() => { getNewData(days) }, [days]) return ( <DataContext.Provider value={{ days, data, daysChangeHandler }} > {props.children} </DataContext.Provider> ) }
修改说明
- 调整了状态和函数的声明顺序,保证函数引用的是最新的状态。
- 给请求方法加了显式的天数入参,彻底规避闭包旧值问题。
- 移除了
setDays的错误回调写法,改用useEffect监听天数变化自动触发请求,保证每次请求的参数都是最新的。 - 用async/await优化了异步请求的写法,逻辑更清晰。
内容的提问来源于stack exchange,提问作者Giustino Sulpizio
相关产品推荐
相关产品推荐

