Create a Global State with React Context 🦾, No Redux, No third party library at all, pure React for Global State.
React Context for global state with pure React
What is React Context?
A typical React application consists of many Components, things get pretty complex as an application grows. If you are using props to pass state
values from your parent component to the child component, things will become more complex pretty soon, and you will end up passing props to infinite levels down in your component tree, which makes debugging really complicated.
Then Redux
or any other state management library enter into the play, but no matter how good are those, it is just another library to handle along with your pure React application. Considering that, React introduced Context API
with React 16. Let's see what it is capable of.
React Context and Redux:
Context is designed to share data that can be considered “global” for a tree of React components, such as the current authenticated user, theme, or preferred language.
This is what React official docs have to say about React Context
, Before we start talking about some code, let's have a look at what Redux
provides that we can replicate in our application with React Context
.
As you can see in the above picture, we have actions
, reducers
, and store
to manage our state in Redux
. You will not believe me, but we can achieve the same functionality with React Context
as you move forward in this article. Let's break down the above image.
Actions - These are just functions
, we call an action whenever we want to make changes in our application data, most of the time, these functions are simple API calls, which are capable to change the global state through dispatch
.
Reducer - Aah! its name is really confusing for beginners, but no worries, these are also simple functions, which would take the old state
and action
as an argument and return the new state
as an object.
Store - A store is an immutable object tree in Redux. You can think of it as a state container that holds the application's state.
Now we have got the idea of actions
, reducer
, and store
, let's jump into the coding.
Let's create a StoreProvider
HOC with React Context:
First We will Start a simple React App with the help of
create-react-app
, run the command given below.$ npx create-react-app context-demo
Just create a folder inside
src/
with the namestore
.Create a file named
index.js
inside thesrc/store/
folder.Create a file named
reducer.js
inside thesrc/store/
folder.Let's write our
StoreProvider
HOC inside thesrc/store/index.js
file.import React from "react"; import { reducer } from "./reducer"; // Create a initial state object const initialState = { "name": "Gaurav", } // Create a context with initial state export const Context = React.createContext(initialState); // State Provider to wrap the whole application const StoreProvider = (props) => { const [state, dispatch] = React.useReducer(reducer, initialState); const { children } = props; return ( <Context.Provider value={[state, dispatch]}>{children}</Context.Provider> ); }; // Default export the StoreProvider export default StoreProvider;
Explanation: First we have to create an initial
state
object to initialize the globalstate
andcontext
, you can keep it empty also. Then we need to create aContext
using the initialstate
object. Oncecontext
creation is done, you can create your ownStoreProvider
component to wrap the whole application inside thisprovider
and make your globalstate
accessible everywhere in your application.You have also noticed that
React.useReducer
is using areducer
andinitialState
to initialize the[state, dispatch]
. We have not created thereducer
yet, let's jump into the next section to create areducer
.
Create a Reducer to utilize the useReducer
hook:
Let's start with the reducer
, we are aware of how reducer
works. Let's create one for our demo application. Just open the reducer.js
that we have created in the last section and write this code.
export const reducer = (state, action) => {
// Check the type of action using switch-case
switch (action.type) {
// if action is 'CHANGE_MY_NAME'
case 'CHANGE_MY_NAME':
// return new immutable state object
return {
...state,
name: action.payload.name,
};
// default
default:
return state;
}
};
Explanation: This is a simple reducer, which is taking state
and action
as an argument and checking the type
of action
which has been dispatched then returning a new state
object accordingly.
Integrate the StoreProvider
with our Application:
Now that we have created our StoreProvider
HOC and a reducer
, it is time to use these things in our application do some cool stuff with them.
Open your
src/index.js
file.Import the
StoreProvider
component in this file.import StoreProvider from "./store";
Now just wrap your
App
inside thisStoreProvider
like this.<StoreProvider> <App /> </StoreProvider>
Now we are all set up and ready to use the state
and modify the state
. Let's do some more cool stuff.
Accessing the global state inside our components tree:
We can access the global state
object in any of our components
using the context
that we have created, but we will do it in a much easier way by creating our own custom hook
, Let's do it.
Open your
src/store/index.js
file again.Write this code just above the
StoreProvider
component and below thecontext
creation code.export const useStore = () => { // Below line will return -> [state, dispatch] return React.useContext(Context); };
Explanation: We are creating a custom
hook
nameduseStore
, which will return the currentstate
anddispatch
function to makestate
modifications through reducers.Let's see how it works in
App.js
component.Open your
src/App.js
file and erase everything in this file, and write this code.import React from 'react'; import { useStore } from "./store"; function App() { const [state, dispatch] = useStore(); return <h1>{state.name}</h1> } export default App;
Explanation: The
initialState
object that we had created earlier in this article is being used in this code.{state.name}
is coming directly from the global state. Hope you have got the idea of a globalstate
. Similarly, you can use the globalstate
from anywhere in your application.
But the trickier part is to make the modification in our global state
through actions
as we do in redux
. But we have got that too, in the above code, you can see that useStore
hook is also returning the dispatch
function, which we will use to make the modification in our global state
through reducers
let's do it.
Modifying the global state inside our components tree:
Let's rewrite our App.js
component with some new functionality.
import React from 'react';
import { useStore } from "./store";
function App() {
const [state, dispatch] = useStore();
const handleChange = (event) => {
dispatch({
type: 'CHANGE_MY_NAME',
payload: {
name: event.target.value
}
})
}
return (
<div>
<input type="text" name="name" onChange={handleChange}/>
<h1>{state.name}</h1>
</div>
)
}
export default App;
Explanation: Now that you see this is the simplest use of dispatch
to modify our global state. The input
element is connected to h1
element value indirectly through React Context
and global state
. In simple words, as you type in the input
element, the value of global state
will change using dispatch
Conclusion:
React is great, React Context is also great, but when it comes to debugging the Context
, that's the toughest part of it. If you are planning to use context
in a large-scale React application, then Redux
will be a much smarter choice because of the features that you will get with it.
You can use context
whatever the way you want it to, you can also create some actions
to perform an `API call, I am leaving this all up to you, it depends on how creative you are with your React skills
Thanks for making it to the End of this article. If you found any mistakes in this article, please do inform me, I would appreciate it.
That's it for today in this blog, if you are finding any difficulty following this blog, you can find the complete code example in this codesandbox
, the link is given below.
External Links:
Code Sandbox
A Project of mine
For more such crispy blogs daily, follow DevJunction, subscribe to our newsletter and get notified.
Social Links
- LinkedIn: https://www.linkedin.com/in/mnamegaurav/
- YouTube: https://www.youtube.com/c/devjunction
- Website: https://gaurav.devjunction.in/
- GitHub: https://github.com/mnamegaurav
- Instagram: https://www.instagram.com/mnamegaurav/
- Twitter: https://twitter.com/mnamegaurav