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.
相关产品推荐
相关产品推荐

