Editor’s note: This Redux vs. React Hooks comparison article was last updated on 23 June 2023 to consider how effective the React Redux Toolkit is for state management. Read more about Redux Toolkit here.
Redux Toolkit simplifies the use of Redux in our application. However, by using the React Context API, in addition to the useContext
and useReducer
Hooks, which were introduced in React v16.8, we can implement robust state management and avoid prop drilling without the need to import additional libraries.
This results in a fairly effective solution for state management in React applications. And yet, far too many React developers default to Redux for state management without considering the alternatives. In this tutorial, we’ll introduce you to the React Context API for state management and explain how React Hooks and the Context API can replace Redux.
If you’re more of a visual learner, the video below describes the React Context API and offers some reasons why you should replace Redux with React Hooks and Context:
No Title
Try LogRocket for free: https://logrocket.com/?yt5 You don’t really need Redux. In this video, we are going to learn how you can get a lot of the same benefits that you would get from Redux using two Hooks that come with React. 0:00 Introduction 0:40 How React Redux works?
To handle data between disconnected components in React, developers use prop drilling. There is no global state that components can access. Therefore, if you want to pass data from a top-level component to, for instance, a fifth-level component, you’ll have to pass the data as a prop on each level of the tree until you get to your desired component.
This results in writing a ton of extra code, and giving components properties that they will never use also affects their architectural design. To solve this problem, we need to provide a global state that all components can access, no matter how deeply nested they are.
By solving this problem, Redux, an open source JavaScript library for managing application state, became the go-to solution for React developers.
To some extent, Redux works well for state management in React applications and has a few advantages. However, its verbosity makes it difficult to learn, and the extra code needed to get it working can introduce unnecessary complexity.
One alternative to consider when evaluating state management options is Redux Toolkit. Redux Toolkit is a library that provides a simplified and opinionated approach to working with Redux. It addresses some of the challenges associated with traditional Redux and offers a more streamlined development experience.
On the other hand, with React Hooks and the useContext
API, there is no need to install external libraries or add a bunch of files and folders to make our app work. This makes it a much simpler, more straightforward approach to handling global state management in React applications.
Let’s take a closer look at Redux, Redux Toolkit, React Hooks, and the Context API to see how they work, what challenges developers face when using these tools, the scenarios in which each option is suitable, and how using React Hooks and Context can help you overcome some common issues associated with Redux.
Redux is a predictable state container for JavaScript applications that helps us write applications that behave consistently, run in different environments, and are easy to test.
One disadvantage of prop drilling is that it requires us to write a considerable amount of extra code to access data from a top-level component. With Redux, this disadvantage becomes more severe because it requires additional code to set up a global state. Redux requires three main building parts to function: actions, reducers, and store.
Actions are objects that are used to send data to the Redux store. They typically have two properties: a type
property for describing what the action does, and a payload
property that contains the information that should be changed in the app state:
// action.js const reduxAction = payload => { return { type: 'action description', payload } }; export default reduxAction;
type
is usually in all caps with its words separated by underscores. For example, SIGNUP_USER
or DELETE_USER_DATA
.
Reducers are pure functions that implement the action’s behavior. They take the current application state, perform an action, and then return a new state:
const reducer = (state, action) => { const { type, payload } = action; switch(type){ case "action type": return { ["action description"]: payload }; default: return state; } }; export default reducer;
The application’s state is housed in the store. There is only one store in any Redux application:
import { createStore } from 'redux' const store = createStore(componentName);
Because our application can only have one Redux store, to create a single root reducer for all our components, we’ll need the combineReducers
method from Redux. With the considerable amount of code required to set up Redux, imagine what our codebase would look like when we have multiple components to work with.
Even though Redux solves our state management problem, it is time-consuming to use, has a difficult learning curve, and introduces a whole new layer of complexity to our application. Fortunately, the React Context API solves these issues. When combined with React Hooks, we have a state management solution that is less time-consuming to set up, has an easier learning curve, and requires minimal code.
To address the complexity and verbosity of Redux, the Redux team introduced Redux Toolkit, a recommended package that simplifies working with Redux and reduces boilerplate code. Redux Toolkit provides several utilities and abstractions to streamline the Redux workflow:
createSlice
: This utility combines the actions and reducers into a single slice of the Redux state. It automatically generates action creators and reducer functions, reducing the amount of boilerplate code neededconfigureStore
: This function configures the Redux store with sensible defaults. It includes built-in middleware, such as Redux Thunk for handling asynchronous logic, and automatically sets up the Redux DevTools Extension for debuggingcreateAsyncThunk
: This utility simplifies handling asynchronous operations in Redux, such as API calls. It generates asynchronous action creators that dispatch multiple actions to reflect the different stages of the async operation (e.g., loading, success, failure)createEntityAdapter
: This API helps manage normalized data structures in the Redux store. It provides utility functions for working with entities and collections, making it easier to handle CRUD operationsBy leveraging Redux Toolkit, developers can write Redux code in a more concise and intuitive manner, reducing the overall complexity and boilerplate associated with traditional Redux setup. It improves developer productivity and enhances the maintainability of Redux applications.
When to consider Redux Toolkit:
It’s important to note that Redux Toolkit is still based on Redux principles and uses the same underlying concepts. However, it aims to simplify the development experience and address some of the pain points associated with manual Redux setup.
In comparison, React Hooks such as useContext
and useReducer
, combined with the Context API, offer a simpler and more lightweight approach to state management. They are particularly suitable for smaller applications or cases where the complexity of Redux might not be necessary.
By understanding the trade-offs and considering the specific needs of your application, you can make an informed decision about whether to use Redux, Redux Toolkit, or React Hooks with the Context API for your state management solution.
The Context API was introduced in React v16.3. React Context enables you to share data that can be considered global for a tree of React components, like the current authenticated user, theme, or preferred language.
Context provides a way to pass data through the component tree without having to pass props down manually at every level. Essentially, the React Context API is React’s way of managing state in multiple components that are not directly connected.
To create a context, we’ll use the createContext
method from React, which accepts a parameter for its default value:
import {createContext} from 'react'; const newContext = createContext({ color: 'black' });
The createContext
method returns an object with a Provider
and a Consumer
component:
const { Provider, Consumer } = newContext;
The Provider
component makes the state available to all child components, no matter how deeply nested they are within the component hierarchy. The Provider
component receives a value
prop, which is where we’ll pass our current value:
<Provider value={color: 'blue'}> {children} </Provider>
The Consumer
, as its name implies, consumes the data from the Provider
without any need for prop drilling:
<Consumer> {value => <span>{value}</span>}} </Consumer>
Without Hooks, the Context API might not seem like much when compared to Redux. But, when combined with the useReducer
Hook, we have a solution that finally solves the state management problem in React.
Hooks are functions that enable the execution of custom code in React’s functional components. They allow us to hook into React’s core features and handle state management easily.
React Hooks provide an alternative to writing class-based components by allowing us to easily handle state management from functional components. Check out this handy React Hooks cheat sheet.
useContext
HookYou may have noticed that when describing the React Context API, we needed to wrap our content in a Consumer
component, then pass a function as a child so that we could access or consume our state.
Doing so introduces unnecessary component nesting and increases the complexity of our code. The useContext
Hook makes things a lot cleaner and more straightforward. To access our state with the useContext
Hook, we simply need to call it with our created context
as its argument:
import { createContext, useContext } from "react"; const newContext = createContext({ color: 'black' }); const value = useContext(newContext); console.log(value); // this will return { color: 'black' }
Now, instead of wrapping our content in a Consumer
component, we can simply access our state through the value
variable.
useReducer
HookThe useReducer
Hook came with React v16.8. Just like the reduce()
method in JavaScript, the useReducer
Hook receives two values as its argument, a reducer function and an initial state. Then, it returns a new state:
import { useReducer } from 'react'; function reducer(state, action) { switch (action.type) { case 'INCREMENT': return { count: state.count + 1 }; case 'DECREMENT': return { count: state.count - 1 }; case 'RESET': return { count: 0 }; default: throw new Error('Unknown action'); } } export default function Counter() { const [state, dispatch] = useReducer(reducer, { count: 0 }); }
In the code block above, we’ve defined our state and a corresponding method, dispatch
, to handle it. When we call the dispatch
method, the useReducer()
Hook will perform an action based on the type
that our method receives in its action argument:
// ... return ( <> <p>Count: {state.count}</p> <button onClick={() => dispatch({ type: 'INCREMENT' })}>Increment</button> <button onClick={() => dispatch({ type: 'DECREMENT' })}>Decrement</button> <button onClick={() => dispatch({ type: 'RESET' })}>Reset</button> </> )
When the button is clicked, it triggers the dispatch function with the specified action type, which will be handled by the reducer function to update the state accordingly. Check out this example in CodeSandbox.
useReducer
Hook with React ContextTo achieve optimal global state management in our React application, we can combine the power of the Context API and the useReducer
Hook. To set it up, we’ll first create our global state in a store.js
file:
// store.js import { createContext, useReducer } from "react"; const initialState = { color: "red" }; const store = createContext(initialState); const { Provider } = store; const StateProvider = ({ children }) => { const [state, dispatch] = useReducer((state, action) => { switch (action.type) { case "CHANGE_COLOR": return { ...state, color: action.payload }; default: throw new Error(); } }, initialState); return <Provider value={{ state, dispatch }}>{children}</Provider>; }; export { store, StateProvider };
In our store.js
file, we used the createContext()
method from React to create a new context. Remember that the createContext()
method returns an object with a Provider
and Consumer
component. This time, we’ll only use the Provider
component and the useContext
Hook when we need to access our state.
Notice how we used the useReducer
Hook in our StateProvider
. When we need to manipulate our state, we’ll call the dispatch
method and pass in an object with the desired type
as its argument.
In our StateProvider
, we returned our Provider
component with a value
prop of state
and dispatch
from the useReducer
Hook.
To access our state globally, we’ll need to wrap our root <App/>
component in our StateProvider
before rendering it in our ReactDOM.render()
function:
// index.js import { StrictMode } from "react"; import { createRoot } from "react-dom/client"; import App from "./App"; import { StateProvider } from "./store"; const rootElement = document.getElementById("root"); const root = createRoot(rootElement); root.render( <StrictMode> <StateProvider> <App /> </StateProvider> </StrictMode> );
Now, our store context
can be accessed from any component in the component tree. To do so, we’ll import the useContext
Hook from React and the store
from our ./store.js
file:
// ExampleComponent.js import { useContext } from 'react'; import { store } from './store.js'; const ExampleComponent = () => { const globalState = useContext(store); console.log(globalState); // this will return { color: red } };
We’ve seen how we can access our global state. To add and remove data from our state, we’ll need the dispatch
method from our store
context. We only need to call the dispatch
method and pass in an object with type
as its parameter, the action description as defined in our StateProvider
component:
// ExampleComponent.js import { useContext } from 'react'; import { store } from './store.js'; const ExampleComponent = () => { const { state, dispatch } = useContext(store); const changeColor = () => { dispatch({ type: "CHANGE_COLOR", payload: "blue" }); }; return ( <div> <h2>Example Component</h2> <p>Current color: {state.color}</p> <button onClick={changeColor}>Change Color</button> </div> ); }; export default ExampleComponent;
Check out this example in CodeSandbox.
Context API | Redux | |
---|---|---|
Built-in tool | Ships with React | Requires additional installation |
Setup | Minimal setup required | Extensive setup required |
Data type | Suitable for static data | Works with static and dynamic data |
Extensibility | Creation of new contexts from scratch | Easily extendible with new data/actions |
Debugging | Debugging can be challenging | Powerful Redux Dev Tools available |
Code organization | UI logic and state management in the same component | Separation of UI and state management logic |
It’s important to consider the complexity and specific requirements of your project when deciding whether to use Redux or the Context API. Both approaches have their strengths and choosing the right one will depend on the scale, nature, and goals of your application.
In this tutorial, we explored the differences between using Redux for state management in React apps and using the React Context API with the useContext
and useReducer
Hooks.
When we use Redux for state management, we have to deal with prop drilling, meaning we have to write a lot of extra code just to get our application started. By using Context to nest components within components, all the functionality from the parent component is available in the child components.
I hope you enjoyed this article, and be sure to leave a comment if you have any questions.
Install LogRocket via npm or script tag. LogRocket.init()
must be called client-side, not
server-side
$ npm i --save logrocket // Code: import LogRocket from 'logrocket'; LogRocket.init('app/id');
// Add to your HTML: <script src="https://cdn.lr-ingest.com/LogRocket.min.js"></script> <script>window.LogRocket && window.LogRocket.init('app/id');</script>
Hey there, want to help make our blog better?
Join LogRocket’s Content Advisory Board. You’ll help inform the type of content we create and get access to exclusive meetups, social accreditation, and swag.
Sign up nowBuild scalable admin dashboards with Filament and Laravel using Form Builder, Notifications, and Actions for clean, interactive panels.
Break down the parts of a URL and explore APIs for working with them in JavaScript, parsing them, building query strings, checking their validity, etc.
In this guide, explore lazy loading and error loading as two techniques for fetching data in React apps.
Deno is a popular JavaScript runtime, and it recently launched version 2.0 with several new features, bug fixes, and improvements […]
48 Replies to "React Hooks vs. Redux: Do Hooks and Context replace Redux?"
Ebenezer, this is a most excellent primer on using these relatively new technologies! For the past few months, I’ve had a steep learning curve on using Hooks and Context in the most effective way possible. Me and my colleagues now have some pretty good patterns working for us but are always trying to improve.
Follow-up article suggestion: Show the community how to write tests for each of the entities you’ve mentioned, namely Context and Reducers. This is something I’m working through now and there doesn’t seem to be many articles on the subject.
The global / lifted up state with useContext + useState/useReduce combo is possible way, but be aware about the performance problems – the whole app (down from provider lever) is re-rendered on every state change. Have a look into Hookstate – supercharged useState which allows to lift the state up to global space, is as simple as useState itself and has got incredible performance – https://github.com/avkonst/hookstate (disclaimer: I am a maintainer)
Andrew, I’d like your advice on something: My colleagues and I have been having a debate about whether to have one global instance of the Context state (or Hookstate) or whether to have multiple smaller instances of the state where there is no need to share the state between different parts of an app.
Interested in your thoughts on this!
There is the best practice in software engineering: “local (more isolated) variable is better than global (more accessible)”. Applying it to react state, the most local is per component state. The next level is the state lifted up to the parent component, when multiple peer / same level components need to share access to the same state (typical case is multi-field forms). The next level is the state per root component or global state when multiple components in different branches of DOM hierarchy need access to the same state. So, lift your state up when you need it but do not open more than you need it. It will give you more maintainable software. Hookstate allows me to lift up and down easily when I need it.
The usual practice in software engineering can be said as something like “use different variables to hold not related data”. It means it is OK to have multiple global state variables or multiple local variables. For example, I keep user account state and app settings configurable by a user in two separate variables, although both are usually global as require sharing across the whole app. Hookstate helps me with this too.
Thanks, Andrew. I’ve always followed the same practice as well. This is why, for each of 3 modal forms I’ve built, each has their own Context. One downside of this is that the child forms (Add Vehicle and Add User) inside the first 2 modal forms are both used in the 3rd modal form as well. This has resulted in some duplicate code in the Contexts, Reducers, and Actions but we have definitely achieved code separation.
Hooks and context are not a replacement for Redux. And you can’t use Sagas.
I wonder why there is a need to pass the reducer (useReducer results).. why not just pass the functions and variables to providers vulue, so there is NO need to use dispatch function when calling state change. Use useState, and pass the results to the provider, so on the consumer components just call the function that alter the state. If there is some heavy logic before altering the state why not wrap it on function first before passing. My point is whats the benefit of calling
dispatch(“UPDATE_USER”,true) where as you can directly call
updateUser(true) function without the ceremony of useReducer hooks
Impressed by hookstate and this article. Thank you very much.
Nice article so far. I got confused by the code snippet in `Setting up our store`. Turned out the code snippet is scrollable. I noticed that by accident. Was pretty confusing..
Is it just me that thinks this is the same amount of boilerplate?
Without any of the features that make redux worth using.
How do I use this inside a class component? How do I ‘dispatch’ an action to update state?
Great article. Apparently the only difference between the two(when trying to decide which to use), is that Redux can handle frequent state changes while Context API cannot.
Nice @ how blog post completely missed that Redux is a few lines of code, uses context internally, and has dev tools + you don’t need to dumpster dive in codebases (along with time travel, a very simple pattern, middleware, consistent interfaces, selectors, immutability and much lower likelihood to miss render waste, without diving into debugger, etc). TLDR: don’t MVC or work on teams, just wing it and live in debugger/memorize all your code111
Yes, it seems like redux with more steps.
I would only agree with you if it’s for a small web application not being planned to scale, otherwise I strongly disagree. You lose A LOT of things by not using Redux, not just “few advantages” as you mentioned. A lot of optimization under the hood is done by Redux through serialization & the connect HOC.
Please read this:
https://blog.isquaredsoftware.com/2018/03/redux-not-dead-yet/
https://www.reddit.com/r/reactjs/comments/bqf5ot/can_anyone_tell_me_why_hooks_have_exploded/eo6fe6e/?context=10000
Agree with anon. If you end up with a store and reducer, why not use redux in the first place? With the new redux hooks API, the usage is way simpler and the boilerplate is light. Add caching to selectors and you get awesome perfs.
It’s really good, got me started using context, thank you
@Ebenezer: Same question here + 1 more,
1. How do I use this inside a class component (as by Tiago)
2. After updating the state from inside the sub-components, the state should be returned back and GUI refreshed as well?
-> -> -> Show Logged in as Yes or No based on a boolean in the store.
I put a button in the Header component to update the loggedIn to true, when I click the button, the reducer gets executed properly but the Text in header (expected Logged In to change from No to Yes) does not change.
Can you please help?
Regards,
SG
Hi Shailendra, Hooks can’t be used directly in a class component, although, the React Context API can be used with class based components. Yomi did a good job explaining the React Context API with class-based examples: https://blog.logrocket.com/how-and-when-to-use-reacts-new-context-api-b584e41b2704/
For your second question, can you confirm that you’re using the useContext Hook to access your store? Also if you could share a code snippet or screenshot, that would be helpful.
– Ebenezer
Glad to know it helped you @infamousgodhand
Hi Tiago, Hooks can’t be used directly in a class component, although, the React Context API can be used with class based components. Yomi did a good job explaining the React Context API with class-based examples: https://blog.logrocket.com/how-and-when-to-use-reacts-new-context-api-b584e41b2704/
Hi Robert, thanks! I’ll keep that in mind.
Hi Ebenezer,
Yes, I’m using useContext in the header.js to consume the User state.
import { Actions, store } from “../store/UserCtx”;
const Header = () => {
const User = useContext(store);
….
….
const changeState = () => {
console.log(“Changing state”, User);
dispatch(Actions.LOGIN);
};
….
….
Logged in : {User.state.loggedIn?’Yes’:’No’}
Cheers!
SG
Is it possible to use this pattern with multiple roots? For example many mini apps in a legacy project?
ReactDOM.render(
,
document.getElementById(‘component’)
);
ReactDOM.render(
,
document.getElementById(‘anotherComponent’)
);
I do not believe so as each StateProvider have it’s own store that is not shared or am I wrong?
Amen Brother ! Thank You for this article !
Context api used badly is as bad as using global state. Re-usability goes out of the window. Cascading the props down more than one level is well known anti-pattern and should be avoided. If you use redux that way no wonder that it creates layers of complexity. And believe me so will Context API.
Hooks (and context) are here predominantly to look after local component state. In that case you do not want to place component logic on application store as it has nothing to do with application logic. e.g. typeahead component which has relatively complex but still independent local logic and local state.
Thanks Rolando, I’m really glad you found this helpful!
Thanks for pointing out, Christian
Redux/Context is only needed if you want to up your game and pass props from Parent to Child rather than using regular props system to pass from Parent to nth Child. Context system will always be direct no matter how big your application is. It’s worth a shot to check it out. It is a lot more advanced. However, learning advanced methods won’t hurt. If anyone wants to check out my application where I used it in react-native here’s the link:
To find context go to src/context and check it out how I used it with api calls.
https://github.com/graysonm23/Native-Blog
Couldn’t you just separate out useState for each instance then only rerender specific components when that specific instance of state in changed? Instance is probably the wrong word
All the downsides you listed to Redux are quite elegantly solved in Redux-Toolkit. Boilerplate reduced so much it’s less LOC than a context-based solution.
Redux isn’t overly complex. It’s the simple flux pattern. If you use the RTK you can separate out “slices” of your store just like you would in context EXCEPT you get the out-of-the box performance benefits, debugging, time travel, middleware (like sagas and thunks) and you CLEANLY separate your business logic from your UI state.
One of the main problems I see is people approaching solutions with the idea of simplicity. That’s all well and good, if your app is truly simple. However, this is not usually the case. We build complex applications in the real world and ESPECIALLY if we don’t control the API we need a good state management solution for our business data. This is where Redux shines.
It’s opinionated with a great architecture: flux.
Using the Redux-Toolkit will net you LESS CODE (yes read that again) LESS CODE that a similar implementation in Context.
AND you get debugging, time-travel, middleware, performance, etc, etc right out of the box.
Before you write any more articles, go use the Redux Toolkit. Seriously. You need to right now if you still think that Redux is full of boilerplate. That was true a few years ago, but boy has it changed.
Thanks for explaining things in clarity! 🙂
These methods can be a good alternative, but the complexity of these codes looks like that of the React-Redux method taught in my bootcamp. For example, the code lines of useReducer look almost the same as Redux reducer, at least to a beginner like me.
Also… Hooks are not covered in my bootcamp. Oops! >_<
I have almost most of my app with context api. but as I notice the more you rely on context the more your codes are hard to manage and hard to refactor. so I prefer Redux because it make the app state scalable. but for some part of my app I prefer context api. like managing permissions or localization
This is a fantastic article Ebenezer, it certainly opens up a lot of possibilities, especially around not having to rely on a 3rd party for global state management. It cemented knowledge around those specific hooks for me as well.
I’ve got some feedback on the article:
– You mention “The useReducer Hook came with React 16.7.0”, but according to the React official docs, it came in 16.8
– You also mention “the useReducer Hook receives two values as its argument” which is correct, but the next sentence isn’t; “— in this case, the current state and an action”. The arguments for the useReducer hook are the reducer function and an initial state. The arguments to the reducer are the values you described.
I found it funny and ironic that the Log Rocket plug advertises that you can “debug your Redux apps”, when this article advocates to not use Redux, lol.
Again, thanks for writing this intellectually stimulating piece.
Hi Kes, thanks for the feedback. I explained the arguments for the useReducer hooks incorrectly and the React version was probably a misinformation. The React docs is a lot richer now. I’ll ask for these to be updated.
If I were to rewrite the entire article at the moment, I would add more of Redux advantages and why it might still be a good option with its recent updates. So, not entirely against Redux anymore.
Thanks for taking your time to read!
I tried using React Context as a global state manager and it ended badly. Context is re-rendering eveyrthing on it’s path. Long story short I had to rewrite the entire project and by doing it I saw the possibility to create my own state manager. I would really appreciate some support https://www.npmjs.com/package/store-me
But why write your own state manager?
Reinventing the wheel (and getting burned) by jumping on the “Context/Hooks is better than Redux” bandwagon should have taught you a lesson – use a proven solution, i.e. Redux, rather than saving a couple of minutes by not having to “npm install redux” and not having to set up a store and a root reducer.
The whole “Context/Hooks is better than Redux” thing is a fad – the core concepts that you use with Context/Hooks are exactly THE SAME as what you use with Redux.
The value used in the context is two completely different things. At first it’s the global state object, and then it’s an object with state and dispatch properties. That was extremely confusing.
And to the people who say just to use Redux: you are creating your own implementation. You are gaining full control and understanding of your state flow for a few extra lines of code. It’s an extremely small price to pay.
Awesome reply..
I love this article, it explains these hooks very clearly and gives very good example code.
… but there is an accident error in the sample code snippet, which is really hard to find.
const app = (
);
the above app is assigned to a literal JSX expression, not a function component,
the right one shoud be:
const app = () => (
);
otherwise, the ReactDom.render wont render it.
FYI.
REDUX SUX! There’s way too much wiring effort and repetition involved! Many people have forgotten the DRY (Don’t Repeast Yourself) principle! Do less with more!
How then, please do share the wisdom with us?
What I see here (Context/Hooks) is for all means and purposes exactly the same as what you’d do with Redux, namely:
– define a Store
– define a Reducer
– define Actions
– use “dispatch”
and so on …
In what way is this different or “better” than Redux then? I say it’s a fad, the emperor has no clothes, lol … let’s just establish that obvious fact, before descending into vacuous Redux-bashing.
The issue I have with useContext, is when you find a way to split it into multiple files, they cannot re-use functions from eachother. For example: https://stackoverflow.com/questions/71276497/createcontext-multiple-files-and-share-functions-state-with-each-other. With redux, you can re-use the code across multiple files (reducers/actions)
I have the same problem with this article as I have with the numerous other “Hooks and Context is better than Redux” articles: it’s misleading, and arguably not true, and I’ll explain why I think so.
So let me quote the following blanket statement that I encountered in the article:
“Its verbosity makes it really difficult to learn, and the extra code needed to get it working can introduce a lot of unnecessary complexity”
That’s highly subjective, and in my opinion not true, because:
– Redux introduces the concept of immutable state – Context and Hooks ALSO uses immutable state
– Redux introduces Actions and Dispatch – Context and Hooks ALSO uses Actions and Dispatch
– Redux introduces the concept of Reducers – Context and Hooks ALSO uses Reducers
In other words, the learning curve of Redux and Context/Hooks are largely the same, because the core concepts that need to be mastered are the same!
There are just two things that Redux requires, which Context/Hooks doesn’t: setting up the Store, and setting up the Root Reducer. Now guess what – any React dev who’s serious about using Redux should be using Redux Toolkit, and if you use Redux Toolkit then setting up the Store and the Root Reducer become trivially simple.
Redux also seems to always get bashed for its “boiler plate” or “verbosity”. That’s also not holding water, because with Context/Hooks you’re ALSO writing these “verbose” actions and reducers – same same … and, guess what (here we go again) – if you use Redux with Redux Toolkit you can cut out the largest part of that boiler plate. Does Context/Hooks come with similar tooling?
Finally, there’s a big risk with Context/Hooks – if not implemented correctly, it can result in unnecessary component re-renders. Redux comes with a “connect” function which is highly optimized in preventing unnecessary component re-renders, and reproducing this same functionality with Context/Hooks is not a simple thing to do.
So to summarize, my “contrary” advice in case you have an app that’s a bit more than tiny and trivial, and which needs global state management, then don’t try to reinvent the wheel, just go with Redux from the start, because:
– the three core concepts are identical anyway (hence 90% of the learning curve is identical)
– works out of the box, no need to waste time reinventing the wheel
– optimized to prevent unnecessary component re-renders
– Redux Toolkit cuts out most of the boilerplate (which you’d have with Context/Hooks as well anyway)
And finally – suppose you start with Context/Hooks because it’s “simple” (at least they make you believe so), and as your app grows you find that you’d really be served better by Redux – now you need to rewrite a lot of code … not necessary if you just install Redux right away (and use it in virtually the same way as you would with Context/Hooks).
Do not use context API as state management. It is very poor with performance and very verbose. The issue with hooks are the following:
– It is verbose, you need to wrap every component under the context provider
– If you wrap the root app then any change in state re-renders the entire react tree
– ever change to the context will make any component wrapped to re-render
Context is not meant for state management. If you try to use it as such, at the moment you apps start having some more complex iterations, and 2-3 level nested component that need states, you will find the need to replace it.
To date the best library for state management, in my experience, is redux for react.
“react-context-slices” solves once for all the problem of state management with Context API. It allows you to define slices of Context. In this way only components consuming the state value of a slice will update. And it’s 0 boilerplate/verbose.
lol, useReducer + Context = Redux Lite
why should i swap redux for an inferior version of itself?
Use zustand simple yet effective. No need to wrap your component with provider.