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>
);
};
Using the context and passing the context values for child component
<AppProvider>
<ChidA />
<ChidB />
</AppProvider>;
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>
);
};
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)
Wow wow wow, superb explainantion on using Content API with custom hooks.
A very neatly written explanation of a very neat implementation of Context API! 👌🏼👌🏼👌🏼
Thanks :)