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

React数据获取后消失:Context传递用户数据失效问题排查

问题描述

我通过Context与Provider实现用户详情的获取,将数据存入state变量与sessionStorage中,期望无需通过props即可为任意组件提供该数据。尝试实现一种按需获取userData的机制:当访问userData时自动触发API调用(必要时)。

控制台显示已成功获取到用户数据,但组件无法读取该数据。例如在ExampleComponent中访问userData.name时无内容,页面仅显示<h1>Username is </h1>。

相关代码如下:

UserDataProvider.jsx

import React, { useState, useContext, createContext } from "react";
import axios from 'axios'

const UserContext = createContext({})

export const theUser = () =>  useContext(UserContext)

const default_info = {
                            name: null,
                            age: null,
                            hobbies: [],
                        }


export const UserDataProvider = ( { children } ) => {


    const [ userData, setUserData ] = useState(getUserData())

    //gets user state from session storage OR a set of defaults OR from the server
    async function getUserData(){
        var data = JSON.parse(sessionStorage.getItem("userData"))
        if (data == "undefined" || data  == null){
           console.log("no data in session - fetching from server")
           data = await FetchUserData()
           return data 
        }
    
        console.log("Found data")
        console.table(data)
        return data


    }

    async function FetchUserData(){
        var body_json = {"getinfo": 1}
        try{
            await axios.post('/api/user_info', {
                headers: {
                    'Content-type':'application/json', 
                    'Accept':'application/json',
                    withCredentials: true
                },
                body: JSON.stringify(body_json)
            }).then((response) => {
                if (response.statusText == "OK"){
                    var userDataObject = {
                        name:   response.data['name'],
                        age:    response.data['savings'],
                        hobbies:  response.data['hobbies'],
                    }
                    
                    setUserData(userDataObject)
                    sessionStorage.setItem('userData', JSON.stringify(userDataObject))
                    return userDataObject
                }
                else return null

            });  
    
        } catch(error){
            console.error(error)
            return null
        }
    }

    const accessibleObjects = { 
       userData

    }


    return (
        <UserContext.Provider value={accessibleObjects}>
            { children }
        </UserContext.Provider>
    )
}

main.jsx

import { UserDataProvider } from './context/UserDataProvider.jsx';

ReactDOM.createRoot(document.getElementById('root')).render(
  <React.StrictMode>
    <AuthProvider>
      <UserDataProvider>
        <Router >
          <App />
        </Router>
      </UserDataProvider>
    </AuthProvider>
  </React.StrictMode>,
)

问题分析与修正方案

你的代码存在几个关键问题,导致组件无法正确读取userData:

1. useState初始化使用异步函数的错误

useState(getUserData())中,getUserData是异步函数,返回值是Promise而非实际用户数据。这会导致初始state是Promise对象,组件读取时自然拿不到正确值。

修正方法:
改用useEffect处理异步初始化逻辑,初始state设为默认值:

const [userData, setUserData] = useState(default_info);
const [isLoading, setIsLoading] = useState(true);

useEffect(() => {
  async function initUserData() {
    const storedData = JSON.parse(sessionStorage.getItem("userData"));
    let finalData;
    
    if (storedData) {
      console.log("Found data in sessionStorage");
      console.table(storedData);
      finalData = storedData;
    } else {
      console.log("no data in session - fetching from server");
      finalData = await FetchUserData();
      sessionStorage.setItem('userData', JSON.stringify(finalData));
    }
    
    setUserData(finalData);
    setIsLoading(false);
  }
  initUserData();
}, []);

2. axios请求参数格式错误

axios.post的正确格式是axios.post(url, data, config),你错误地将body和headers放在了同一个对象里,且手动JSON.stringify请求体(axios会自动处理)。

修正方法:

async function FetchUserData() {
  const body_json = { getinfo: 1 };
  try {
    const response = await axios.post('/api/user_info', body_json, {
      headers: {
        'Content-type': 'application/json',
        'Accept': 'application/json',
      },
      withCredentials: true
    });
    
    if (response.status === 200) { // 用status判断比statusText更可靠
      return {
        name: response.data.name,
        age: response.data.savings, // 注意此处字段名是savings,确认是否为笔误
        hobbies: response.data.hobbies,
      };
    } else {
      return default_info;
    }
  } catch (error) {
    console.error(error);
    return default_info;
  }
}

3. 按需获取逻辑的补充

若要实现“访问userData时自动触发请求”,可以通过getter属性包装userData,同时维护loading状态避免重复请求:

const accessibleObjects = {
  get userData() {
    // 若当前为默认值且未在加载中,触发请求
    if (JSON.stringify(userData) === JSON.stringify(default_info) && !isLoading) {
      initUserData();
    }
    return userData;
  },
  isLoading
};

注:更稳妥的方式是在组件中结合loading状态判断,避免getter中异步操作导致的状态异常。

4. 组件中正确使用Context

确保组件中正确调用theUser()获取上下文:

// ExampleComponent.jsx
import { theUser } from './context/UserDataProvider';

function ExampleComponent() {
  const { userData, isLoading } = theUser();
  return (
    <h1>Username is {isLoading ? 'loading...' : userData.name}</h1>
  );
}

完整修正后的UserDataProvider.jsx

import React, { useState, useContext, createContext, useEffect } from "react";
import axios from 'axios'

const UserContext = createContext({
  userData: { name: null, age: null, hobbies: [] },
  isLoading: false
})

export const theUser = () => useContext(UserContext)

const default_info = {
  name: null,
  age: null,
  hobbies: [],
}

export const UserDataProvider = ({ children }) => {
  const [userData, setUserData] = useState(default_info);
  const [isLoading, setIsLoading] = useState(true);

  async function FetchUserData() {
    const body_json = { getinfo: 1 };
    try {
      const response = await axios.post('/api/user_info', body_json, {
        headers: {
          'Content-type': 'application/json',
          'Accept': 'application/json',
        },
        withCredentials: true
      });
      if (response.status === 200) {
        return {
          name: response.data.name,
          age: response.data.savings,
          hobbies: response.data.hobbies,
        };
      } else {
        return default_info;
      }
    } catch (error) {
      console.error(error);
      return default_info;
    }
  }

  async function initUserData() {
    setIsLoading(true);
    const storedData = JSON.parse(sessionStorage.getItem("userData"));
    let finalData;
    
    if (storedData) {
      console.log("Found data in sessionStorage");
      console.table(storedData);
      finalData = storedData;
    } else {
      console.log("no data in session - fetching from server");
      finalData = await FetchUserData();
      sessionStorage.setItem('userData', JSON.stringify(finalData));
    }
    
    setUserData(finalData);
    setIsLoading(false);
  }

  useEffect(() => {
    initUserData();
  }, []);

  const accessibleObjects = {
    get userData() {
      if (JSON.stringify(userData) === JSON.stringify(default_info) && !isLoading) {
        initUserData();
      }
      return userData;
    },
    isLoading
  };

  return (
    <UserContext.Provider value={accessibleObjects}>
      {children}
    </UserContext.Provider>
  )
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.19 20:04:55