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

useContext首次页面刷新无法读取值 触发JSON解析错误

React Context异步传值首屏刷新JSON解析异常

问题复现代码

App.jsx

export const LoginContext = React.createContext();
export const DetailsContext = React.createContext();

function App() {
  const username = localStorage.getItem("bankDetails");
  const [userDetails, setUserDetails] = useState({});
  const [isValid, setisValid] = useState(false);

  useEffect(() => {
    if (username !== null) {
      Axios.post("http://localhost:3001/userDetails", {
        username: username,
      }).then((res) => {
        if (res.data.err) {
          console.log("err");
        } else {
          setUserDetails(res.data.details[0]);
          setisValid(true);
        }
      });
    }
  }, []);

  return (
    <LoginContext.Provider value={{ isValid, setisValid }}>
      <DetailsContext.Provider value={{ userDetails, setUserDetails }}>
        <Router>
          <Routes>
            <Route ... />
          </Routes>
        </Router>
      </DetailsContext.Provider>
    </LoginContext.Provider>
  );
}

export default App;

Transactions.js

function Transactions() {
  const { isValid } = useContext(LoginContext);
  const { userDetails, setUserDetails } = useContext(DetailsContext);
  const [allDetails, setAllDetails] = useState([]);
  const [transactions, setTransactions] = useState([]);

  useEffect(() => {
    console.log(userDetails);
    Axios.get("http://localhost:3001/transactTo").then((rest) => {
      setAllDetails(rest.data);
    });
    // setTransactions(JSON.parse(userDetails.transactions));
  }, [userDetails]);

  return isValid ? <h1>Valid</h1> : <h1>Not Valid</h1>
}
export default Transactions;

问题现象

  • 页面首次硬刷新时,通过useContext获取的userDetails首次控制台打印为空对象,等待组件重渲染后才能拿到正确数据对象
  • 取消setTransactions(JSON.parse(userDetails.transactions))行的注释后,首次渲染阶段直接抛出错误:Unexpected token u in JSON at position 0
  • 异常仅在页面硬刷新时触发,通过路由导航从其他页面跳转进入时无该问题
  • 尝试新增依赖项为allDetails的useEffect执行交易数据解析逻辑,问题仍然存在,无效修复代码如下:
useEffect(() => {
  setTransactions(JSON.parse(userDetails.transactions));
}, [allDetails]);

根本原因

  • 异步时序问题:App组件中userDetails的初始状态是空对象{},用户详情的接口请求是异步执行的,组件首次挂载时Context下发的就是初始空对象,子组件首次渲染拿到的userDetails自然不存在transactions属性
  • 报错触发逻辑:首次渲染时userDetails.transactions值为undefined,JSON.parse接收到undefined参数时,会先将其转为字符串"undefined",解析第一个字符u时不符合JSON语法,直接抛出解析错误
  • 路由跳转无异常的原因:前端路由跳转是单页应用内部导航,App根组件不会重新卸载挂载,跳转前接口请求已经完成、userDetails已经被更新为正确值,子组件挂载时拿到的是加载完成的完整数据,不会触发空值解析
  • 依赖allDetails修复无效的原因:allDetails对应的接口请求和userDetails的接口请求是完全独立的两个异步任务,返回时机没有绑定关系,allDetails更新不代表userDetails已经加载完成、存在transactions字段,属于依赖项配置错误。

修复方案

  1. 给解析逻辑加非空守卫,等字段存在时再执行JSON解析,修改Transactions组件中对应useEffect:
useEffect(() => {
  console.log(userDetails);
  Axios.get("http://localhost:3001/transactTo").then((rest) => {
    setAllDetails(rest.data);
  });
  // 先判断transactions字段存在再执行解析
  if (userDetails?.transactions) {
    setTransactions(JSON.parse(userDetails.transactions));
  }
}, [userDetails]);
  1. 优化初始状态配置,增加加载态拦截,避免未加载完成时渲染业务逻辑:
// App.jsx 中将userDetails初始值改为null,区分未加载/已加载空数据的状态
const [userDetails, setUserDetails] = useState(null);

// Transactions.jsx 渲染前增加加载判断
if (!isValid || !userDetails) {
  return <div>数据加载中...</div>
}
return <h1>Valid</h1>
  1. 修正useEffect依赖项:解析transactions的逻辑依赖userDetails的变化,不要将无关联的allDetails设为依赖项,避免逻辑和依赖不匹配导致的执行时机错误。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.26 09:57:19