Rethinking State Management in React with useContext Hooks

Omkar Bhavare
4 min readDec 15, 2023

The article will discuss the useContext hook and how it can be used in a React application. It talks about how React is a popular JavaScript library for developing user interfaces and offers developers various means of handling state and data flow in an app. Among these instruments is the useContext hook, which permits transmitting data through many components without prop drilling.

🤔 What is Context in React?

In React, “context” is a way of sharing information among various components without directly passing it through props. It simplifies the process of passing data through different parts of your application without manually including it as props at every step. Context becomes particularly handy when dealing with data that is considered global or needs to be accessed by multiple components in your app.

🤔 Why is useContext Important?

Sharing Data Across Components: The big deal with useContext is that it lets you easily share data between different components. This comes in handy when your data is needed by various components scattered across your app.

Avoiding Prop Drilling: Prop drilling is the process of passing data from one component to another through props. Imagine passing a message through a chain of people just to get it to the right person. In React, that’s called “prop drilling,” and it can be a bit of a hassle. useContext acts like a shortcut, skipping the line of people and making sure your data gets where it needs to go without the drama.

🤔 How useContext Works:

💡 Create a Context [ createContext() ]: Creates a special box to store and share data (context) in React.

const MyContext = React.createContext();

💡 Provide the Context [ .Provider ]: Wraps components with the created box, making the stored data available to all nested components.

<MyContext.Provider value={/* some value */}>
{/* Your component tree */}
</MyContext.Provider>

💡 Consume the Context [ useContext() ]: Allows functional components to easily grab and use the shared data from the context box, eliminating the need for manual prop passing.

const myValue = useContext(MyContext);

🔥 Practical Example

/src
|-- components
| |-- TaskProvider.js
| |-- TaskList.js
| |-- TaskForm.js
|-- App.js
|-- index.js

TaskProvider.js

// TaskProvider.js
import React, { createContext, useContext, useState } from 'react';

// Step 1: Create a context
const TaskContext = createContext();

const TaskProvider = ({ children }) => {
// Step 2: Set up state for tasks
const [tasks, setTasks] = useState([]);

// Step 3: Define functions to manipulate tasks
const addTask = (newTask) => setTasks([...tasks, newTask]);
const deleteTask = (taskId) => setTasks(tasks.filter((task) => task.id !== taskId));
const toggleTaskCompletion = (taskId) =>
setTasks(tasks.map((task) => (task.id === taskId ? { ...task, completed: !task.completed } : task)));

// Step 4: Provide the context and functions to the components
return (
<TaskContext.Provider value={{ tasks, addTask, deleteTask, toggleTaskCompletion }}>
{children}
</TaskContext.Provider>
);
};

// Step 5: Create a custom hook for accessing the context
const useTaskContext = () => useContext(TaskContext);

export { TaskProvider, useTaskContext };

TaskList.js

// TaskList.js
import React from 'react';
import { useTaskContext } from './TaskProvider';

const TaskList = () => {
// Step 6: Use the custom hook to access the context
const { tasks, deleteTask, toggleTaskCompletion } = useTaskContext();

return (
<div>
<h2>Task List</h2>
<ul>
{tasks.map((task) => (
<li key={task.id} style={{ textDecoration: task.completed ? 'line-through' : 'none' }}>
{task.text}{' '}
<button onClick={() => toggleTaskCompletion(task.id)}>
{task.completed ? 'Unmark' : 'Mark'}
</button>
<button onClick={() => deleteTask(task.id)}>Delete</button>
</li>
))}
</ul>
</div>
);
};

export default TaskList;

TaskForm.js

// TaskForm.js
import React, { useState } from 'react';
import { useTaskContext } from './TaskProvider';

const TaskForm = () => {
// Step 7: Use the custom hook to access the context
const { addTask } = useTaskContext();
const [newTask, setNewTask] = useState('');

// Step 8: Handle task addition
const handleAddTask = () => {
if (newTask.trim() !== '') {
const task = { id: Date.now(), text: newTask, completed: false };
addTask(task);
setNewTask(''); // Clear input field after adding task
}
};

return (
<div>
<h2>Add Task</h2>
<input
type="text"
placeholder="Enter task"
value={newTask}
onChange={(e) => setNewTask(e.target.value)}
/>
<button onClick={handleAddTask}>Add Task</button>
</div>
);
};

export default TaskForm;

App.js

// App.js
import React from 'react';
import { TaskProvider } from './components/TaskProvider';
import TaskList from './components/TaskList';
import TaskForm from './components/TaskForm';

const App = () => {
return (
// Step 9: Wrap the entire app with the TaskProvider
<TaskProvider>
<div>
<h1>Task Manager</h1>
<TaskForm />
<hr />
<TaskList />
</div>
</TaskProvider>
);
};

export default App;

index.js

// index.js
import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';

ReactDOM.render(
<React.StrictMode>
<App />
</React.StrictMode>,
document.getElementById('root')
);

In this project, we’ve created a Task Manager application where tasks are managed using the useContext hook. The TaskProvider component sets up the context and provides functions to manipulate tasks. The TaskList and TaskForm components use the custom hook useTaskContext to access the context and interact with tasks.

📚Conclusion :

The useContext hook, combined with the Context API, forms a robust system for handling state in React apps. This approach eliminates prop drilling, simplifying your code and making it more maintainable. As you build complex React applications, a solid understanding of useContext will be crucial in delivering scalable and efficient state management solutions.

📚Earlier Post:

👉 The Art of Lazy Loading
👉 Inner Workings of Browsers and Websites
👉 The Browser Rendering Process
👉 React Hooks: useState & useEffect
👉 Understanding React Functional Components and Hooks

🔍 Coming up next:

👉 Props & State
👉 useReducer Hook
👉 useRef Hooks

Stay tuned for more insights into the world of Web development! 🚀📦

🤝 Let’s connect on LinkedIn: https://www.linkedin.com/in/omkarbhavare/

--

--

Omkar Bhavare

Passionate developer, blogger, and problem solver. Crafting code, sharing insights, and building innovative projects. 🚀