Redux is a state management solution for web applications. Although it is widely used with React, it can be used with any Javascript app. Although Redux is a great state management solution, it is boilerplate-y in nature and adds to the overall size of your app.
React is a UI library that does not ship with its own state management solution - or does it?
React Context API
In a typical React application, data is passed top-down (parent to child) via props, but this can be cumbersome for certain types of props (e.g. locale preference, UI theme) that are required by many components within an application. Context provides a way to share values like these between components without having to explicitly pass a prop through every level of the tree.
On its own, the context api is not a substitute for Redux since you cannot replicate the complex action-reducer paradigm without other hooks
Disclaimer
A word of disclaimer before we start. I would suggest that the method i am documenting here only be used in small projects. If you are building something huge, you should still use Redux. It provides a lot more functionality through Thunks, Saga and Reselect.
The solution
Sharing the auth state with all the components of your component tree is a common usecase. Let's implement that using the context api and the useReducer hook.
Use the useReducer hook to create a reducer function
import React, { useReducer } from "react";
const initialState = {
user: null,
};
export const AUTH_STATE_CHANGED = "AUTH_STATE_CHANGED";
const reducer = (state, action) => {
switch (action.type) {
case AUTH_STATE_CHANGED:
return {
user: action.payload,
};
}
return state;
};
I have created a simple reducer function similar to what you would see in a Redux project by passing the hook a reducer function and an initial state.
Using the React Context API, we can now create a context that we want to drill down the app. The authState
object is the state that you want to be passed down to your components and actions
object contains all the actions that you would typically use with Redux. The useReducer
hook returns a dispatch
function just like Redux
const AuthContext = React.createContext();
const AuthProvider = (props) => {
const [authState, dispatch] = useReducer(reducer, initialState);
const actions = {
authStateChanged: (user) => {
if (user) {
dispatch({ type: AUTH_STATE_CHANGED, payload: user });
}
},
};
return (
<AuthContext.Provider
value={{
authState: authState,
authActions: actions,
}}
>
{props.children}
</AuthContext.Provider>
);
};
We can now export this
export { AuthProvider, AuthContext };
Wrap the component you want to access the state from. Since i want to be able to access the authState from anywhere in my app, I will wrap my App
component. If you do not want the whole app to be able to access the state, you can scope the state by selectively wrapping the components that need to be able to access the state
import { AuthProvider } from "./authContext";
export default function App() {
return (
<AuthProvider>
<Login />
</AuthProvider>
);
}
}
Now to access the state from any component inside my app eg. Login screen
import { AuthContext } from "./authContext";
const Login = (props) => {
const { authState, authActions } = React.useContext(AuthContext);
const login = () => {
authActions.authStateChanged({ name: "Burhanuddin" });
}
return (
<div>
{authState.user.name}
<button onClick={() => login()}>
Login
</button>
</div>
);
};
With this you can replicate Redux inside React without any external dependencies
Connect with me
You can follow me on DEV or connect with me on Twitter. Subscribe to my newsletter
Top comments (3)
If you have as many actions as usually you have in redux this might get quite expensive as every change will recreate all those actions and all components that depend on any of the action or any of the state. That is a fundamental difference between redux and context. Redux handles memoization well and selects only what you need. Also you create actions only once and not multiple times. So because the dispatch function never changes, so should also the actions never change.
so what will be better efficient way of using context in enterprise projects
Use it for state that does not change often - stuff like theme preference, language preference. Context is not a state management solution, it's a dependency injection mechanism