Context API vs. Redux: When and Why to Use Them in React
Published: 2024-07-02 16:03:07

Before starting to explore the differences and use cases of both Context API and Redux, it is essential to understand why these two solutions were developed.

In simple React, we can pass down data from parent components to child components. The parent component is where your main component is rendering. For example:

Let's say we have a component named Greet.js, and this component is rendering in App.js, making App.js its parent component. If we pass a constant firstName with the value "John", it will look like this:

```jsx
//App.js
export const App = () => {
  const firstName = "John";

  return (
    <Greet name={firstName} />
    <Profile name={firstName} />

  );
}
```
```jsx
// Greet.js
export const Welcome = ({ name }) => {
  return <h1>Welcome : {name}</h1>;
}
```
```jsx
//Profile.js
export const Profile = ({ name } => {
return <h1> userName : {name} </h1>
```
This above method also known as Prop Drilling .Passing props can become inconvenient when you need to pass some prop deeply through the tree, or if many components need the same prop the prop drilling becomes complex and then for passing props we use context API.

**Context API**:

Context is a way to pass data through the component tree without having to pass it down manually at every level.It's beneficial for sharing data that can be considered "global" for a tree of React components, such as the current authenticated user, theme, or preferred language.
There are three step to implement Context API:

**Create a Context**: Define a context to hold the state.

**Provide Context**: Wrap the top-level component with the context provider.

**Consume Context**: Use the context in the child components to access the state.

**1-Create a Context**
```jsx
// UserContext.js
import React, { createContext, useState } from 'react';

const UserContext = createContext();

const UserProvider = ({ children }) => {
  const [name, setName] = useState("John");

  return (
    <UserContext.Provider value={{ name }}>
      {children}
    </UserContext.Provider>
  );
};

export { UserContext, UserProvider };
```
**2-Provide Context**
```jsx
// App.js

import React from 'react';
import { UserProvider } from './UserContext';
import Welcome from './Welcome';
import Profile from './Profile';

const App = () => {
  return (
    <UserProvider>
      <div>
        <Welcome />
        <Profile />
      </div>
    </UserProvider>
  );
};

export default App;
```
**3-Consume Context**
```jsx
// Welcome.js
import React, { useContext } from 'react';
import { UserContext } from './UserContext';

const Welcome = () => {
  const { name } = useContext(UserContext);

  return <h1>Welcome: {name}</h1>;
};

export default Welcome;
```
```jsx
// Profile.js
import React, { useContext } from 'react';
import { UserContext } from './UserContext';

const Profile = () => {
  const { name } = useContext(UserContext);

  return <h1>userName: {name}</h1>;
};

export default Profile;
```
Using the Context API allows data to flow anywhere in the component tree, making it a superior method for managing application state compared to prop drilling. However, as applications grow in complexity and certain side effects become challenging to manage within individual components, Redux emerges as a powerful solution.

**React Redux**

Redux simplifies state management by centralizing it through a global store. It not only eliminates the need for prop drilling but also provides an efficient way to handle side effects using middleware. This approach ensures that side effects, such as asynchronous data fetching or logging, are managed centrally, keeping components focused solely on UI rendering.

Let's understand it with example : 
These steps involved in Redux data flow:

**Create Action** : Define action to be perform

**Create Reducer** : Define how to perform action and update it 

**Create Store** : Recieved updated state from Reducer and make it available to call in any component.

**1.Create Action**
```jsx
// userActions.js
export const setName = (name) => ({
  type: 'SET_NAME',
  payload: name,
});

```
**2.Create Reducer**
```jsx
// userReducer.js
const initialState = {
  name: 'John', // initial state
};

const userReducer = (state = initialState, action) => {
  switch (action.type) {
    case 'SET_NAME':
      return { ...state, name: action.payload };
    default:
      return state;
  }
};

export default userReducer;
```
**3.Create Store **

```jsx
// store.js
import { createStore } from 'redux';
import userReducer from './userReducer';

const store = createStore(userReducer);

export default store;

```
Wrap your application with the Redux Provider component to make the store available to all components.
```jsx
// App.js
import React from 'react';
import { Provider } from 'react-redux';
import store from './store';
import Welcome from './Welcome';
import Profile from './Profile';

const App = () => {
  return (
    <Provider store={store}>
      <div>
        <Welcome />
        <Profile />
      </div>
    </Provider>
  );
};

export default App;
```
Now, you can use this globally in any component by using useSelector hook :
```jsx
// Welcome.js
import React from 'react';
import { useSelector } from 'react-redux';

const Welcome = () => {
  const name = useSelector(state => state.name);

  return <h1>Welcome: {name}</h1>;
};

export default Welcome;
```
**Conclusion**:

In the end, whether you choose React's Context API or Redux depends on what your application specifically requires and the particular challenges it faces.