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

React中如何为CitiesContext设置createContext初始值?

问题

在React中创建了Context但未设置初始值,已成功为AuthContext添加初始值,但不清楚如何为CitiesContext执行相同操作,需要指导。以下是已完成的AuthContext代码,以及需要修改的CitiesContext代码(所有函数逻辑正常):

已完成的AuthContext代码

import { createContext, useContext, useReducer } from "react";

// const AuthContext = createContext();
const AuthContext = createContext({
  isAuthenticated: false,
  user: {},
  login: () => {},
  logout: () => {},
});

const initialState = {
  user: null,
  isAuthenticated: false,
};

function reducer(state, action) {
  switch (action.type) {
    case "login":
      console.log("works");
      return { ...state, user: action.payLoad, isAuthenticated: true };

    case "logout":
      return { ...state, ...initialState };
    default:
      throw new Error("Unkonw action");
  }
}

function AuthProvider({ children }) {
  const [{ user, isAuthenticated }, dispatch] = useReducer(
    reducer,
    initialState
  );

  function login(email, password) {
  }

  function logout() {
  }

  return (
    <AuthContext.Provider value={{ user, isAuthenticated, login, logout }}>
      {children}
    </AuthContext.Provider>
  );
}

function useAuth() {
  const context = useContext(AuthContext);
  return context;
}

// eslint-disable-next-line react-refresh/only-export-components
export { useAuth, AuthProvider };

需要修改的CitiesContext代码

import { createContext, useContext, useEffect, useReducer } from "react";

const BASE_URL = "http://localhost:8000";

//add initial value here
const CitiesContext = createContext();

const initialState = {
  cities: [],
  isLoading: false,
  currentCity: {},
  error: "",
};

function reducer(state, action) {
  switch (action.type) {
    case "loading":
      return { ...state, isLoading: true };

    case "cities/loaded":
      return { ...state, isLoading: false, cities: action.payLoad };

    case "city/loaded":
      return { ...state, isLoading: false, currentCity: action.payLoad };

    case "city/created":
      return {
        ...state,
        isLoading: false,
        cities: [...state.cities, action.payLoad],
        currentCity: action.payLoad,
      };

    case "city/deleted":
      return {
        ...state,
        isLoading: false,
        cities: state.cities.filter((city) => city.id !== action.payLoad),
        currentCity: {},
      };

    case "rejected":
      return { ...state, isLoading: false, error: action.payLoad };

    default:
      throw new Error("Action unkown");
  }
}

function CitiesProvider({ children }) {
  const [{ cities, isLoading, currentCity, error }, dispatch] = useReducer(
    reducer,
    initialState
  );
  // const [cities, setCities] = useState([]);
  // const [isLoading, setIsLoading] = useState(false);
  // const [currentCity, setCurrentCity] = useState({});

  useEffect(function () {
    async function fetchCities() {
      dispatch({ type: "loading" });

      try {
        const res = await fetch(`${BASE_URL}/cities`);
        const data = await res.json();
        dispatch({ type: "cities/loaded", payLoad: data });
        // setCities(data);
      } catch (err) {
        dispatch({ type: "rejected", payLoad: `error loading data ` });
      }
    }
    fetchCities();
  }, []);

  async function getCity(id) {
    if (Number(id) === currentCity.id) return;

    dispatch({ type: "loading" });
    //
    try {
      // setIsLoading(true);
      const res = await fetch(`${BASE_URL}/cities/${id}`);
      const data = await res.json();
      // setCurrentCity(data);
      dispatch({ type: "city/loaded", payLoad: data });
    } catch (err) {
      dispatch({ type: "rejected", payLoad: `error loading data ` });
    }
  }

  async function createCity(newCity) {
    dispatch({ type: "loading" });

    try {
      // setIsLoading(true);
      const res = await fetch(`${BASE_URL}/cities`, {
        method: "POST",
        body: JSON.stringify(newCity),
        headers: {
          "Content-Type": "application/json",
        },
      });
      const data = await res.json();
      // setCities((cities) => [...cities, data]);
      dispatch({ type: "city/created", payLoad: data });
    } catch (err) {
      dispatch({ type: "rejected", payLoad: `error creating city data ` });
    }
  }

  async function deleteCity(id) {
    dispatch({ type: "loading" });

    try {
      // setIsLoading(true);
      await fetch(`${BASE_URL}/cities/${id}`, {
        method: "DELETE",
      });
      // setCities((cities) => cities.filter((city) => city.id !== id));
      dispatch({ type: "city/deleted", payLoad: id });
    } catch (err) {
      dispatch({ type: "rejected", payLoad: `error deleting city ` });
    }
  }

  return (
    <CitiesContext.Provider
      value={{
        cities,
        isLoading,
        currentCity,
        error,
        getCity,
        createCity,
        deleteCity,
      }}
    >
      {children}
    </CitiesContext.Provider>
  );
}

function useCities() {
  const context = useContext(CitiesContext);
  return context;
}

export { CitiesProvider, useCities };
解决方案

给CitiesContext添加初始值的逻辑和AuthContext完全一致:

  • 先明确CitiesContext.Provider提供的所有字段:状态字段包括cities、isLoading、currentCity、error,方法包括getCity、createCity、deleteCity
  • 给createContext传入一个对象,状态字段用initialState里的初始值,方法用空函数占位(避免组件在Provider外调用时抛出错误)

修改后的CitiesContext定义如下:

const CitiesContext = createContext({
  cities: [],
  isLoading: false,
  currentCity: {},
  error: "",
  getCity: () => {},
  createCity: () => {},
  deleteCity: () => {},
});

修改后的完整CitiesContext代码

import { createContext, useContext, useEffect, useReducer } from "react";

const BASE_URL = "http://localhost:8000";

// 已添加初始值
const CitiesContext = createContext({
  cities: [],
  isLoading: false,
  currentCity: {},
  error: "",
  getCity: () => {},
  createCity: () => {},
  deleteCity: () => {},
});

const initialState = {
  cities: [],
  isLoading: false,
  currentCity: {},
  error: "",
};

function reducer(state, action) {
  switch (action.type) {
    case "loading":
      return { ...state, isLoading: true };

    case "cities/loaded":
      return { ...state, isLoading: false, cities: action.payLoad };

    case "city/loaded":
      return { ...state, isLoading: false, currentCity: action.payLoad };

    case "city/created":
      return {
        ...state,
        isLoading: false,
        cities: [...state.cities, action.payLoad],
        currentCity: action.payLoad,
      };

    case "city/deleted":
      return {
        ...state,
        isLoading: false,
        cities: state.cities.filter((city) => city.id !== action.payLoad),
        currentCity: {},
      };

    case "rejected":
      return { ...state, isLoading: false, error: action.payLoad };

    default:
      throw new Error("Action unkown");
  }
}

function CitiesProvider({ children }) {
  const [{ cities, isLoading, currentCity, error }, dispatch] = useReducer(
    reducer,
    initialState
  );

  useEffect(function () {
    async function fetchCities() {
      dispatch({ type: "loading" });

      try {
        const res = await fetch(`${BASE_URL}/cities`);
        const data = await res.json();
        dispatch({ type: "cities/loaded", payLoad: data });
      } catch (err) {
        dispatch({ type: "rejected", payLoad: `error loading data ` });
      }
    }
    fetchCities();
  }, []);

  async function getCity(id) {
    if (Number(id) === currentCity.id) return;

    dispatch({ type: "loading" });
    try {
      const res = await fetch(`${BASE_URL}/cities/${id}`);
      const data = await res.json();
      dispatch({ type: "city/loaded", payLoad: data });
    } catch (err) {
      dispatch({ type: "rejected", payLoad: `error loading data ` });
    }
  }

  async function createCity(newCity) {
    dispatch({ type: "loading" });

    try {
      const res = await fetch(`${BASE_URL}/cities`, {
        method: "POST",
        body: JSON.stringify(newCity),
        headers: {
          "Content-Type": "application/json",
        },
      });
      const data = await res.json();
      dispatch({ type: "city/created", payLoad: data });
    } catch (err) {
      dispatch({ type: "rejected", payLoad: `error creating city data ` });
    }
  }

  async function deleteCity(id) {
    dispatch({ type: "loading" });

    try {
      await fetch(`${BASE_URL}/cities/${id}`, {
        method: "DELETE",
      });
      dispatch({ type: "city/deleted", payLoad: id });
    } catch (err) {
      dispatch({ type: "rejected", payLoad: `error deleting city ` });
    }
  }

  return (
    <CitiesContext.Provider
      value={{
        cities,
        isLoading,
        currentCity,
        error,
        getCity,
        createCity,
        deleteCity,
      }}
    >
      {children}
    </CitiesContext.Provider>
  );
}

function useCities() {
  const context = useContext(CitiesContext);
  return context;
}

export { CitiesProvider, useCities };

内容的提问来源于stack exchange,提问作者Niv G.

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.09 09:57:06