DEV Community

Cover image for The Secrets To Creating React Context API with Custom hook 🪝
Mehul Jariwala
Mehul Jariwala

Posted on

The Secrets To Creating React Context API with Custom hook 🪝

For current project, I had to use Context api to solve the props drilling problem. I didn't know anything about how we can combine the context api with custom hooks, and it took a couple of reading hours to get to start with it. This short article hopes to help others save the time it took for me to understand the basics of it.

Idea behind this was,

Let's get started with custom hooks using the react context API. The concept is that we use a context api to give props to inner-level components, with each hook handling the logic of the entire context api.

Problem we are trying to address using React context apis

lets start with simple example that how to create context api

Creating the context

import React, { createContext, useState } from "react";
const AppContext = createContext();

const { Provider } = AppContext;

export const AppProvider = (props) => {
  const [firstName, setFirstName] = useState("");
  const [middleName, setMiddleName] = useState("");
  const [lastName, setLastName] = useState("");
  const [userDetails, setUserDetails] = useState({});
  const [productDetails, setProductDetails] = useState([]);
  const [storeDetails, setStoreDetails] = useState({});
  const [cartDetails, setCartDetails] = useState({});
  const [userStep, setUserStep] = useState(null);
  const [itemDetails, setItemDetails] = useState([]);

  const updatingCartInfo = (cartItem) => {
    let newCartItem = { ...cartDetails, cartItem };
    setCartDetails(newCartItem);
  };

  const newProductAdded = (product) => {
    let newProductDetails = [...productDetails];
    newProductDetails.push(product);
    setProductDetails(newProductDetails);
  };

  return (
    <Provider
      value={{
        firstName,
        middleName,
        lastName,
        userDetails,
        productDetails,
        storeDetails,
        cartDetails,
        userStep,
        itemDetails,
        setFirstName,
        setMiddleName,
        setLastName,
        setUserDetails,
        setProductDetails,
        setStoreDetails,
        setCartDetails,
        setUserStep,
        setItemDetails,
        updatingCartInfo,
        newProductAdded,
      }}
    >
      {props.children}
    </Provider>
  );
};



Enter fullscreen mode Exit fullscreen mode

Using the context and passing the context values for child component

<AppProvider>
  <ChidA />
  <ChidB />
</AppProvider>;

Enter fullscreen mode Exit fullscreen mode

When you create a context and give all of its values to its child component, the values are mashed up, and all of the logic is written exclusively in the context api.

So now it's time to discuss the react custom hooks inside the context api, and context apis are concerned to passing the props, so each custom hook will handle the state to reduce the complexity of the context api (for instance, rather than having to handle all the logic inside context apis, why don't use react custom hooks to separate the logic?).

Example of context api with custom hooks.

import React, { createContext, useState } from "react";
const AppContext = createContext();

const { Provider } = AppContext;

//can be in separate file
const useUserInfoState = () => {
  const [firstName, setFirstName] = useState("");
  const [middleName, setMiddleName] = useState("");
  const [lastName, setLastName] = useState("");
  const [userDetails, setUserDetails] = useState({});

  return {
    firstName,
    middleName,
    lastName,
    userDetails,
    setFirstName,
    setMiddleName,
    setLastName,
    setUserDetails,
  };
};

//can be in separate file
const useCartInfo = () => {
  const [cartDetails, setCartDetails] = useState({});
  const updatingCartInfo = (cartItem) => {
    let newCartItem = { ...cartDetails, cartItem };
    setCartDetails(newCartItem);
  };
  return { cartDetails, updatingCartInfo };
};

//can be in separate file
const useProductInfo = () => {
  const [productDetails, setProductDetails] = useState([]);
  const newProductAdded = (product) => {
    let newProductDetails = [...productDetails];
    newProductDetails.push(product);
    setProductDetails(newProductDetails);
  };

  const newProductDelete = (product) => {
    let newProductDetails = [...productDetails];
    newProductDetails.splice(product.id, 1);
    setProductDetails(newProductDetails);
  };
  return { productDetails, newProductAdded, newProductDelete };
};

export const AppProvider = (props) => {
  const userInfoState = useUserInfoState();
  const cartInfoState = useCartInfo();
  const productInfoState = useProductInfo();

  return (
    <Provider value={{ userInfoState, cartInfoState, productInfoState }}>
      {props.children}
    </Provider>
  );
};

Enter fullscreen mode Exit fullscreen mode

As a result of this, we were able to have the AppProvider manage all props for passing down to the child component and custom hooks handle the logic behind context.

Conclusion

You can come up with numerous ways to tackle the problem, or you can use redux. Reducer to separate logic from context api, thus if we don't have redux in the app, you can handle it with this approach, which we've already used in our project and is more clean and understandable.

Please leave a comment and let me know what you think :)

Thank you for spending the time to read this article.

Happy coding 💻

Top comments (3)

Collapse
 
sahil9818 profile image
Sahil Khatri

Wow wow wow, superb explainantion on using Content API with custom hooks.

Collapse
 
arunabharjun profile image
Arunabh Arjun

A very neatly written explanation of a very neat implementation of Context API! 👌🏼👌🏼👌🏼

Collapse
 
mehuljariwala profile image
Mehul Jariwala

Thanks :)