I created a context in react but never used an initial value . I have add it to one context but idk how to do it in the other one.
can u please show me how to do it?
(i removed all unrelated code but assume the functions have code that works
this is the one i have done myself:
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 };
now i want to do same in this code but idk how:
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 };
2
Answers
Basically the initial value of your context is what you want as your starting value of what you are going to pass to your application and base on your code this is the value you pass to your application
Example you want to start the cities as empty array or isLoading as false you can add that to your initial value
Trying this out in my editor, I noticed the issue that your createContext call:
const CitiesContext = createContext()
does not include any parameter, which is invalid. What you could do is just pass the
initialState
object as the parameter of createContext.Then you would get to the other issue, which is adding the rest of the missing values based on what you’re passing to the provider. You have to expand the
initialState
object so that the expected types match. It’s missinggetCity
,createCity
, anddeleteCity
.The outcome would be something like this: