React函数组件中如何在Context函数内获取并使用最新上下文值
React Context状态更新后函数获取旧值的解决方案
问题核心原因
- App.js中的状态更新错误:
paginate函数里调用setPageIndex(currentPage)时,currentPage是调用函数时的旧值(React状态更新是异步的,不会立刻改变变量引用),且完全没必要通过currentPage中转,直接用传入的页码参数即可。 - 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
相关产品推荐
相关产品推荐

