Redux vs. HOC Pattern with useContext() and useReducer() - reactjs

Why would you use the external Redux library over React's own useContext() and useReducer() hooks, with the Higher-Order Component (HOC) pattern?
Installing and importing an additional, large library such as Redux increases the size of your application and consumes more resources. Redux is essentially using the HOC pattern, takes advantage of the JavaScript reducer pattern, and uses a "context" to keep tack of global state.
React HOCs take care the tree hell issue created by context providers, in large apps:
const App = () => {
return (
<Provider1>
<Provider2>
<Provider3>
<Layout>
<Main />
</Layout>
</Provider3>
</Provider2>
</Provider1>
)
}
I've tried to do research on the differences and pros/cons, but haven't come to a conclusion. The only major advantage I see with using Redux is that it has its own browser extension, Redux DevTools, that's helpful for debugging and inspecting global state and HOCs. In your opinion, which is better to use and why? Redux, or React useContext() and useReducer() (with HOCs and useMemo())?

Redux uses context, but not for state value propagation, but just to pass the never-changing store reference down. As such, Redux' context will never cause any rerender. After that, subscriptions to store changes are used with selectors and the useSyncExternalStore hook.
By just using useReducer and useContext, you cannot recreate a performant state management library, as any update to any part of the value passed through the context will rerender all consumers. You can get around that by using many contexts, but ends as soon as you have dynamically added properties or a dynamic number of values you want to propagate performantly.
In short: use a state mgmt library. It doesn't need to be Redux, you can also look into other libraries as MobX, Recoil, XState, Jotai, Zustand, Valtio, HookState or others - but Context is not suited to actually manage state. It's just a mechanism to propagate a single value that rarely changes to a few consumers.
You can read more on this in Why React Context is Not a "State Management" Tool (and Why It Doesn't Replace Redux).

Related

Is Redux internally using context API?

I had an interview, where the interviewer asked me if redux uses context API internally. Pls provide a detailed description if yes. Thanks
Redux doesn't use context api, it's a javascript library for state management. You can use Redux with any application- like (react, angular, vue, svelte, etc). However, for using redux with react applications, you need react-redux which is the official react bindings for redux.
react-redux uses React's context api to make the redux store accessible to all components. The reason why you need react-redux is because, React uses virtual dom - which means you can't manipulate the DOM directly. In other libraries like angular, we use the NgRx library (For angular).
Internally, React Redux uses React's "context" feature to make the
Redux store accessible to deeply nested connected components. As of
React Redux version 6, this is normally handled by a single default
context object instance generated by React.createContext(), called
ReactReduxContext.
Source
Yes, but differently than if you would be doing it by yourself.
If you were to use Context manually, you would usually do value propagation - passing the current state value down the tree. This can lead to very inefficient rerendering behaviour. See this article for a deeper explanation.
React-Redux on the other hand uses context for dependency injection. The store is passed down the tree and will never change, never triggering a rerender. All the rest is done by Redux internally, using manual subscriptions. This is much more performant.

Redux vs Context API and useReducer hook

I have been working in React for past 6 months and do not have any experience with Redux yet. Though I have worked with context api and useReducer hook. I need to convert an existing application to react which will have around 100-120 components. My question is about the choice of state management. With the rise of context api and useReducer hook, Can I rely on these two only Or Redux library is still a better choice ? Articles that I found for comparison are from late 2019 so I couldn't decide.
Please guide
Redux is still a much better choice for large scale.
Let's assume you have 10000 global state variables in the global store. And you need to change one.
Context API
It will rerender all of its consumer components which is unnecessary.
Redux
It allows us to selectively rerender components that subscribed to changed values.
So
Context API is good for small scale but not good for large scale.
Fundamentals are still same for context API before and after useReducer.
I think useReducer and contextAPI should be good enough even for large applications if you don't want the time travel that Redux provides out of box, as a by-product of its design.
For large applications, one could have a large state (or multiple reducers combined via combiner) in Redux, and yet avoid re-rendering of components. This is because components are rendered based on parts of state that it depends upon, using the mapStateToProps and mapDispatchToProps magic. With contextAPI and useReducer one designs global state by breaking it up into Providers such that only the sub-tree affected by a particular sub-part of global state is passed that part of global state via its own provider.
Check this out: https://kentcdodds.com/blog/application-state-management-with-react

Is a React Context basically a mini redux store?

No practical purpose to this question, just tryna connect concepts to get my head around switching from Redux to using useReducer and React contexts - is a Context when used with useReducer` basically a redux store that's only available to components that explicitly import it?
No. Context and Redux are very different tools that solve very different problems.
Context is simply a mechanism to make a single value accessible to a portion of your component tree. It's up to you to write the code that determines what that value is and how it gets updated. This is typically done by storing data in React component state, and creating a value that is passed to a <MyContext.Provider>.
Redux is a separate UI-agnostic state management library that is designed to help you write predictable state update logic and track when, where, why, and how your state has updated over time, with the React-Redux UI bindings layer allowing your React components to interact with that Redux store.
Now, yes, useReducer+useContext do have some similarities to Redux in terms of how your component will interact with them, but they also have very different performance characteristics in terms of when and why your components will re-render.
Please see my extensive post on A (Mostly) Complete Guide to React Rendering Behavior and my additional posts Redux - Not Dead Yet! and React, Redux, and Context Behavior for details on how Redux and Context differ and how
It is not hard to implement the exact logic of react-redux by means of useContext, useReducer and maybe useSelector)
But useContext + useReducer is not a full replacement of Redux.
useReducer is just an alternative to useState.
And useContext comes with https://en.reactjs.org/docs/context.html#caveats
To store multiple values you have to https://en.reactjs.org/docs/context.html#consuming-multiple-contexts

React hooks: are they useful for shared state management, like e.g. Redux?

There is a hype about React hooks. Too much information and I still don't know: does the advent of hooks mean that libs like Redux can be thrown to garbage?
So far, what I understood is hooks are good for stateful functional components, what about shared state?
No, hooks don't totally eliminate the need for Redux. Hooks are mainly as an alternative to implement features that we have to use classes for today:
Local component state
Context
Lifecycle methods and side effects
Other than the above, hooks also provide an easier way to share stateful logic between components.
What is more likely to kill/replace Redux is context instead of hooks, which is a way to share state across components. But IMO context isn't as powerful as Redux stores as there are other features that Redux offers besides a shared state store such as middlewares and a specialized devtool with time-travelling capabilites. There's also a whole learning and tooling ecosystem built around Redux that context doesn't have at the moment as far as I know.
If you use the useReducer hook in conjunction with context like in this example, it'd be very similar to using Redux and for small apps (like a TodoMVC), it might be sufficient. For large apps I don't think just one context and useReducer will be sufficient. You might need multiple of them, and that's where using Redux and composing stores would make sense. You could also combine multiple contexts and useReducer hooks but it might be cleaner to just use Redux.
No, Hooks won't replace Redux, but they can help you write cleaner code, and you won't need to write class components just to use local state or lifecycle methods. That is a great use case right there.
In the past you had to use Redux to make sure a state is persistent between each re-render of the component. But now you can just use useState() method to implement a persistent local state!
You can use useEffect() instead of React lifecycle methods, and you can use useReducer to write quick action creator methods and access a global state!!
Here is a good article about how to use useReducer() method.
Yes but it looks like its still not an official feature. It's still in feature proposal. stage. Many people thought react context would dump redux into the garbage but it turns out it didn't.
Attention please, Redux is just state management. Not a react library. You can use Redux in any project that you want.
In the future, maybe the redux connector (react-redux) will be killed or unused by hooks but the Redux itself it's an awesome library because it brings the order inside an application that has to handle a lot of data and develop by tons of developers.
There may be more use cases where Redux isn't necessary, but no, neither Hooks nor context will "kill" Redux.
I use Redux inside an enterprise application that, before, was a mess there was no source of truth. Redux put order inside the codebase and the logic.
Hooks and Context are not for managing application state in lieu of Redux.
Context is more akin to props in that it solves the nightmare that can become of communicating information from a parent to a child in large, heavily nested enterprise level applications. The downside is that Context is a bit more complex and setting it up can be painful.
Hooks just allow us to use functional components that can now hook into application state without having to turn them into class-based components.
The confusion lies in that you can grab functionality from Redux with a hook like useReducer without the traditional Redux setup.
So like if you were working on a blog application and you wanted to add functionality to update your blogposts, you can apply useReducer like so:
const blogReducer = (state, action) => {
switch (action.type) {
case 'add_blogpost':
return [...state, { title: `Blog Post #${state.length + 1}` }];
default:
return state;
}
};
So that would be your reducer which you would then apply like so:
export const BlogProvider = ({ children }) => {
const [blogPosts, dispatch] = useReducer(blogReducer, []);
You can temporarily create a helper function to dispatch an action object:
const addBlogPost = () => {
dispatch({ type: 'add_blogpost' });
};
You would have to add it to your value prop, the 'add_blogpost'. Anyway, it's just a confusing way of utilizing aspects of Redux on a functional component without using the whole Redux system itself, but again, not a replacement.

using connect's mapToProps vs reading and dispatching to the store as a global?

What's the difference between A) using the connect method of connecting state and dispatch function to a component and B) simply having functions in a component that do the dispatching as well as accessing the store as a global directly?
(Not ES2015)
Quoting from the Redux FAQ on importing the store directly:
While you can reference your store instance by importing it directly, this is not a recommended pattern in Redux. If you create a store instance and export it from a module, it will become a singleton. This means it will be harder to isolate a Redux app as a component of a larger app, if this is ever necessary, or to enable server rendering, because on the server you want to create separate store instances for every request.
I also recently wrote a Reddit comment on why you should use React-Redux and connect instead of talking to the store directly. Quoting that:
First, while you can manually write the code to subscribe to the Redux store in your React components, there's absolutely no reason to write that code yourself. The wrapper components generated by React-Redux's connect function already have that store subscription logic taken care of for you.
Second, connect does a lot of work to ensure that your actual components only re-render when they actually need to. That includes lots of memoization work, and comparisons against the props from the parent component and the values returned by your mapStateToProps function for that component. By not using connect, you're giving up all those performance improvements, and your components will be unnecessarily re-rendering all the time.
Third, by only connecting your top-level component, you are also causing the rest of your app to re-render unnecessarily. The best performance pattern is to connect lots of components in your app, with each connected component only extracting the pieces of data it actually needs via mapStateToProps. That way, if any other data changes, that component won't re-render.
Fourth, you're manually importing the store into your components, and directly coupling them together, thus making it harder to test the components. I personally try to keep my components "unaware" of Redux. They never reference props.dispatch, but rather call pre-bound action creators like this.props.someFunction(). The component doesn't "know" that it's a Redux action creator - that function could be a callback from a parent component, a bound-up Redux action creator, or a mock function in a test, thus making the component more reusable and testable.
And finally, the vast majority of apps built using React and Redux use the React-Redux library. It's the official way to bind the two together, and doing anything else will just confuse other developers looking at your project.
For more info, see:
The Redux FAQ section on performance
The Redux FAQ entry on connecting multiple components
The Redux FAQ entry on components re-rendering too often
The Redux FAQ entry on importing the store directly
The Redux Performance section of my React/Redux links list
And finally, my blog posts Practical Redux, Part 6: Connected Lists, Forms, and Performance and Idiomatic Redux: Why use action creators?.
Source: I'm a Redux maintainer, and author of the Redux FAQ.

Resources