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

React函数组件中如何在Context函数内获取并使用最新上下文值

React Context状态更新后函数获取旧值的解决方案

问题核心原因

  1. App.js中的状态更新错误:paginate函数里调用setPageIndex(currentPage)时,currentPage是调用函数时的旧值(React状态更新是异步的,不会立刻改变变量引用),且完全没必要通过currentPage中转,直接用传入的页码参数即可。
  2. Context函数的闭包陷阱:getVideos函数在组件渲染时创建,会捕获当时的pageIndex变量引用;当pageIndex更新后,旧的getVideos函数仍持有旧的pageIndex,导致调用时拿到过期值。

具体修改方案

方案1:给getVideos传入最新页码(最直接)

修改App.js的paginate函数,直接用传入的参数更新Context状态,并把最新页码传给getVideos:

import React, { useState, useContext } from 'react';
import { AppContext } from './app-context'

const App = () => {
    const { pageIndex, getVideos, setPageIndex } = useContext(AppContext)
    const [currentPage, setCurrentPage] = useState(1);

    const paginate = async (i) => {
        setCurrentPage(i)
        setPageIndex(i) // 直接用最新的i更新Context状态
        getVideos(i) // 把最新页码传给getVideos
    }
    
    return (
        <div>
            <p>Current Page:- {currentPage}</p>
            <ul>
                <li onClick={() => paginate(1)}>1</li>
                <li onClick={() => paginate(2)}>2</li>
                <li onClick={() => paginate(3)}>3</li>
                <li onClick={() => paginate(4)}>4</li>
                <li onClick={() => paginate(5)}>5</li>
            </ul>
        </div>
    )
}

export default App;

修改app-context.js的getVideos函数,接收传入的页码:

import React, { useState } from 'react';

export const AppContext = React.createContext({
    pageIndex: 0,
    setPageIndex: () => {},
    getVideos: async () => {}
});

export const AppContextProvider = ({ children }) => {
  const [pageIndex, setPageIndex] = useState(0);

  async function getVideos(targetPageIndex) {
    // 优先用传入的最新值,兼容不传参的场景
    const currentIndex = targetPageIndex ?? pageIndex;
    console.log(currentIndex); // 现在能拿到最新值
    // TODO: 调用fetch API,使用currentIndex
  }

  const context = {
    pageIndex,
    getVideos,
    setPageIndex
  }
  return <AppContext.Provider value={context}>{children}</AppContext.Provider>
}

方案2:用useCallback绑定依赖(自动更新函数引用)

通过useCallback包裹getVideos,让它在pageIndex变化时重新创建,确保始终捕获最新的状态:

import React, { useState, useCallback } from 'react';

export const AppContext = React.createContext({
    pageIndex: 0,
    setPageIndex: () => {},
    getVideos: async () => {}
});

export const AppContextProvider = ({ children }) => {
  const [pageIndex, setPageIndex] = useState(0);

  // 用useCallback绑定pageIndex依赖,状态变化时函数自动更新
  const getVideos = useCallback(async () => {
    console.log(pageIndex); // 拿到最新值
    // TODO: 调用fetch API
  }, [pageIndex]);

  const context = {
    pageIndex,
    getVideos,
    setPageIndex
  }
  return <AppContext.Provider value={context}>{children}</AppContext.Provider>
}

同时修改App.js的paginate,直接用i更新状态:

const paginate = async (i) => {
    setCurrentPage(i)
    setPageIndex(i)
    getVideos()
}

方案3:用useRef保存最新状态(避免闭包问题)

通过useRef同步pageIndex的最新值,让getVideos始终能拿到最新状态:

import React, { useState, useRef, useEffect } from 'react';

export const AppContext = React.createContext({
    pageIndex: 0,
    setPageIndex: () => {},
    getVideos: async () => {}
});

export const AppContextProvider = ({ children }) => {
  const [pageIndex, setPageIndex] = useState(0);
  const pageIndexRef = useRef(pageIndex);

  // 同步ref和state的最新值
  useEffect(() => {
    pageIndexRef.current = pageIndex;
  }, [pageIndex]);

  async function getVideos() {
    console.log(pageIndexRef.current); // 拿到最新值
    // TODO: 调用fetch API
  }

  const context = {
    pageIndex,
    getVideos,
    setPageIndex
  }
  return <AppContext.Provider value={context}>{children}</AppContext.Provider>
}

App.js的paginate修改为:

const paginate = async (i) => {
    setCurrentPage(i)
    setPageIndex(i)
    getVideos()
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.02 03:05:04