skip to Main Content

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


  1. 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

    {
    cities,
    isLoading,
    currentCity,
    error,
    getCity,
    createCity,
    deleteCity,
    }
    

    Example you want to start the cities as empty array or isLoading as false you can add that to your initial value

    Login or Signup to reply.
  2. 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 missing getCity, createCity, and deleteCity.

    The outcome would be something like this:

    const initialState = {
      cities: [],
      isLoading: false,
      currentCity: {},
      error: '',
      getCity: (id: number) => Promise<void>,
      createCity: (newCity: object) => Promise<void>,
      deleteCity: (id: number) => Promise<void>
    }
    
    //add initial value here
    const CitiesContext = createContext(initialState)
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search