React.useEffect中Promise链式调用状态更新失效:如何临时保存状态或采用正确设计模式?
Hey, I've run into this exact closure issue with React hooks and Promise chains before—let me break down what's happening and how to fix it without sacrificing function independence.
The Root Cause
The problem boils down to closure behavior in React hooks: your useEffect callback captures the initial data state when it runs. Even though getEventData updates the state, functions like getEventBanner_Photo and getAttendees still reference the original data from the initial render because they were defined in that closure. State updates don't retroactively change the data variable in those functions.
Fix 1: Use Functional Updates (Recommended)
React's setState (and setData from useState) accepts a function instead of an object. This function receives the current latest state as its argument, so you don't rely on the stale closure value.
Modify each of your data-fetching functions to use functional updates instead of spreading the stale data variable:
// Updated getEventData async function getEventData() { const response = await fetch('/api/event-data'); const newEventData = await response.json(); // Use functional update to access the latest state setData(prevData => ({ ...prevData, ...newEventData })); } // Updated getEventBanner_Photo async function getEventBanner_Photo() { const response = await fetch('/api/event-banner'); const bannerBlob = await response.blob(); setData(prevData => ({ ...prevData, event_bannerData: URL.createObjectURL(bannerBlob) })); } // Updated getAttendees async function getAttendees() { const response = await fetch('/api/attendees'); const attendeesData = await response.json(); setData(prevData => ({ ...prevData, attendees: attendeesData })); } // Your existing useEffect stays unchanged! React.useEffect(() => { getEventData() .then(getEventBanner_Photo) .then(getAttendees) .catch(err => console.error('Data load failed:', err)); // Always handle errors! }, []);
This way, every setData call uses the most up-to-date state, regardless of when the function was called. Your functions stay independent—they just need this small adjustment to how they update state.
Fix 2: Separate Data Fetching from State Updates
If you want to keep your fetch functions purely focused on getting data (not updating state), you can return the fetched data from each function and handle state updates directly in the useEffect chain. This also avoids closure issues because you're updating state immediately after receiving each result, using functional updates:
// Pure data-fetching functions (no state dependencies) async function getEventData() { const response = await fetch('/api/event-data'); return response.json(); } async function getEventBanner_Photo() { const response = await fetch('/api/event-banner'); return response.blob(); } async function getAttendees() { const response = await fetch('/api/attendees'); return response.json(); } // Centralized state updates in useEffect React.useEffect(() => { getEventData() .then(eventData => { setData(prev => ({ ...prev, ...eventData })); return getEventBanner_Photo(); }) .then(bannerBlob => { setData(prev => ({ ...prev, event_bannerData: URL.createObjectURL(bannerBlob) })); return getAttendees(); }) .then(attendees => { setData(prev => ({ ...prev, attendees })); }) .catch(err => console.error('Data load failed:', err)); }, []);
This approach makes your fetch functions reusable elsewhere (since they don't depend on component state) and keeps state logic centralized in the effect.
Which One to Choose?
- Go with Fix 1 if you want minimal changes and prefer keeping state updates close to where the data is fetched.
- Use Fix 2 if you want strict separation of concerns (data fetching vs. state management) or need to reuse the fetch functions in other components.
内容的提问来源于stack exchange,提问作者Jason Rich Darmawan

