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

React Context的planet状态变undefined排查及state更新写法疑问

问题原因分析

你遇到的planet最终变为undefined的问题,完全是顶层无包裹的if (planet)逻辑导致的,执行流程如下:

  1. 组件首次渲染:planet初始值为undefined,不触发if逻辑,useEffect发起数据请求
  2. 数据请求完成后调用setPlanets(transformedData),将planet赋值为星球数组,触发组件重渲染
  3. 本次重渲染时planet是数组(真值),进入if逻辑,调用setPlanets(planet[0])将planet赋值为数组第一项的星球对象,再次触发重渲染
  4. 第三次重渲染时,planet已经是单个星球对象,而非数组,此时访问planet[0]得到的就是undefined,调用setPlanets(undefined)后planet就被设为undefined,后续渲染不会再进入if逻辑,最终状态停留在undefined
相关问题解答

setPlanets(planet[0])这种直接使用当前state值更新state的写法本身语法没有问题,但有两个明显缺陷:

  • 存在闭包陷阱:如果更新前state已经被其他逻辑修改,当前渲染作用域下拿到的planet可能是旧值,导致更新不符合预期,更稳妥的写法是使用函数式更新:setPlanets(prev => prev[0]),参数prev永远是最新的state值
  • 你的场景下这种写法本身逻辑错误:你用同一个state既存整个星球数组,又存单个选中的星球,逻辑混淆才会触发前面的bug
修复方案

拆分两个独立state分别存储全量星球数据和当前选中星球,避免逻辑冲突:

import React from "react";
import { useState, useEffect } from "react";

export const Context = React.createContext({
  onChooseMoon: () => {},
  onChooseMars: () => {},
});

const ContextProvider = (props) => {
  // 存储全量星球数组
  const [planets, setPlanets] = useState([]);
  // 存储当前选中的星球
  const [currentPlanet, setCurrentPlanet] = useState();

  useEffect(() => {
    fetch("./data.json")
      .then((response) => {
        return response.json();
      })
      .then((data) => {
        const transformedData = data.destinations.map((destination) => {
          return {
            name: destination.name,
            img: destination.images.png,
            desc: destination.description,
            dist: destination.distance,
            travel: destination.travel,
          };
        });
        setPlanets(transformedData);
        // 数据加载完成后默认选中第一个星球
        setCurrentPlanet(transformedData[0]);
      });
  }, []);

  const setMoonHandler = () => {
    setCurrentPlanet(planets[0]);
  };

  const setMarsHandler = () => {
    setCurrentPlanet(planets[1]);
  };

  return (
    <Context.Provider
      value={{
        planet: currentPlanet,
        onChooseMoon: setMoonHandler,
        onChooseMars: setMarsHandler,
      }}
    >
      {props.children}
    </Context.Provider>
  );
};

export default ContextProvider;

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.28 00:06:03