Use React Context API against prop drilling and for modularizing your app

Babek Naghiyev
2 min readJun 22, 2021

Prop drilling is a readability annoyance going on from the date ReactJS got published the first time. This is a simple example:

const GrandParent = () => {
<Parent childId={123} />
}
const Parent = ({childId}) => {
<Child id={childId} />
}
const Child = ({id}) => {
<div id={id} />
}

We need to use this kind of ugly code mostly for our forms and it is intuitively required while refactoring work is done. In all likelihood using a global store like Redux is not a modularized approach. We need to create a tree-like composition similar to a federal state: govern and decide as near to the subject as possible.

Before going on you should take a look at the Ternary design system to profoundly understand the core principles. Don’t forget to clap :)

Here is the folder structure of the standard that we are going to elucidate:

You can add numerous hooks without recreating new Contexts and Providers

This path will grant you a highly modularized technique. You can use Redux for global actions and Context API for file-based state modifications. You are required to name your context and provider as the name of the component. Contact -> ContactContext, HomePage -> HomePageContext. Imagine your base folder (Contact) as a federated state that has its own government and is also dependent on the central government (Redux etc.).

Let’s see some code examples.

ContactContext.js

import { createContext } from 'react';
const ContactContext = createContext(null);
export default ContactContext;

ContactProvider.js

import React from 'react';
import ContactContext from './ContactContext';
import useContactForm from './hooks/useContactForm';
const ContactProvider = ({ children }) => {
const { contactFormProps } = useContactForm();
return (
<ContactContext.Provider value={{ ...contactFormProps }}>
{children}
</ContactContext.Provider>
);
};export default ContactProvider;

hooks/useContactForm.js

import { useState } from 'react';const useContactForm = () => {
const [contactForm, setContactForm] = useState({
name: '',email: '',message: ''
});
/**
* For validation and other middle tasks we use
* a controller function
* In this example we settle form values.
*/
const contactFormController = (target) => {
const {name, value} = target;
setContactForm({
...contactForm,
[name]: value
});
};
return {
contactFormProps: {
contactForm,
contactFormController
},
};
};export default useContactForm;

Let’s wrap our Contact component using the provider

import React from 'react';
import { Form } from './ui/partials';
import { ContactProvider } from './common/context/ContactProvider';
const Contact = () => {
return (
<ContactProvider>
<Form />
</ContactProvider>
);
};export default Contact;

Eventually, our context is ready to be used by our contact form.

...
const { contactForm, contactFormController } =
useContext(ContactContext);
return (
<input name="name" value={contactForm.name} onChange={contactFormController}/>
<input name="email" value={contactForm.email} onChange={contactFormController}/>
<textarea name="message" value={contactForm.message} onChange={contactFormController}/>
...

If you like this publication, please clap and share.
What do you think? Is Context API still useful?

--

--