Is React Context API suitable for large scale applications - reactjs

I am planning to build a large React application which might contain hundreds of components. But not sure what state management system to use between Redux and Context API.
Context API is in-built in React and doesn't need any third party library. It is easy to implement and solves the problem of sharing states at different levels of the component.
But on the other hand Redux is the Industry standard and has support for middleware to perform async actions.
If I choose Context API how can we manage API calls with it. Also do you think it is a good idea to use context for a large application where we might need state objects extensively.

The design benefit from Redux is that the action does not implement. An action is an indication that something happened (for example SAVE_PROFILE_CLICKED) but the action doesn't do anything (like connecting to api, sending data and saving response in state). You can do this with context api but the separation isn't enforced as much and you won't have the redux devtools. The pattern is called event store/sourcing. You could change the reducer and replay the events to see if your changes work and create a consistent state, testing is easier, extending is easier, logic is better isolated and probably many more benefits to be had.
The design also separates writing to state (reducer), side effects (thunk) and reading from it (selectors). This pattern (writing/reading separation) is called cqrs. Your query/selector is separated from the command/reducer. This gives you easier testing, isolation of logic, less chance of duplicate implementation and probably many more benefits.
You can still make a complete mess of your project when using Redux and not fully understand it so using Redux does not guarantee anything.
If I choose Context API how can we manage API calls with it.
You can do it any way you like it, the question is too general to answer.
Also do you think it is a good idea to use context for a large application where we might need state objects extensively.
As stated before; Redux is no guarantee your project won't be a mess. It will give you the tools to implement certain patterns with more ease. Make sure you understand it and it's patterns. Most example applications don't demonstrate why Redux is so powerful as the problem they implement (counter, todo app) isn't complex enough to even warrant using it. I can only advice you would write code that you're comfortable with and can understand.

Related

How much it is mandatory to use state pattern i.e. mobx or redux in developing applications

I have seen it is becoming mandatory to use state pattern i.e mobx or rudux etc for building any react application. I am concerned that how much it is necessary to use these patterns. like if i have an application and have some pages in it each one is populating data with calling some restfull. So we can have handle it by adding some of optimization techniques like useEffect, usememo and usecalback and obviously custom hooks etc. Shouldn't it must be cleared before starting development application that how much we want to track changes in applications and how much global state we want to use. it we want only one global state ie auth status. we can use simple context and doing all with having simple techniques. So that our application become less dependent upon these libraries. If it is not like that which are the requirement that must be cleared before starting an application to decide whether to use state pattern or going with simpler version of react
It's not mandatory. In fact, my startup's codebase doesn't use any state management library. Just useState and for a few special cases we rely on useContext. React even offers useReducer (which is a simplified Redux).
I used Redux for a project and I hated it. If you're going to use it, follow the rules. Redux should be side effect free and immutable. When needing async data, you often have to use complicated middleware and other libraries (e.g. Redux-Sagas).
The good thing is that you can use a state management library for a part of your app. Maybe even another state management library for a different part.
In some cases, it might be useful to use a state management pattern. Certainly when it allows you to make some logic more understandable, readable or testable.
My take away: Always try to keep it simple

Statecharts for Redux

Current State Management Stack: React, RTK/Redux, and Redux-Saga
Here's the high level issue. We have a complex flow and we don't have QA Engineering resources to be able to write the integration tests needed for this. This leads to the following issues:
A lot of context needed to change something in this flow(without introducing bugs)
Having to manually test a lot of different paths in the flow to try and make sure nothing was broken
A huge lack of efficiency
Even with dedicated QA effort, bugs still slip through to production with how many paths there are
I've been looking at xstate and really love the ability to generate statecharts(less context needed, non-technical stakeholder understanding, & seems like it would result in better efficiency moving forward). For state management, we currently use Redux across the platform(changing this would be incredibly out of scope). This leads me to my questions:
Does anyone know of a (well supported)npm package where I can integrate Redux with statecharts?
If not, what are the pros/cons of implementing both xstate and Redux? Xstate would only be for this flow and would need to pull some data from Redux. While Redux state is available to xstate, I'm assuming I wouldn't need to write it in a way that Redux is dependent on xstate.
I'm not super familiar with xstate but I don't want to dive too deep if this ends up being a waste of time/terrible idea.
ALSO - for context, this is a very large repo & the solution needs to be maintainable, readable, and most importantly - scalable
ALSO 2 - The main goal of this is the auto-generated statecharts. We have many hands in this flow and keeping documentation up to date manually is not feasible
You can always use statecharts as Redux reducer functions! In fact, one of the XState devs put together an example repo demonstrating exactly how to do that (as well as using XState services in a Redux middleware for side effects):
https://github.com/mattpocock/redux-xstate-poc

Should we be using redux in the following case?

I'm working on an enterprise application which is huge on forms, there are pages and pages full of forms. Normally when it's just form, we could simply use a library like formik or react-hook-forms, but what I see time and again is when something changes, there's a business requirement to do something, which means I'm mutating form values programmatically.
We are currently using useEffect and put all those business logic side effects on components, but then it feels like I'm mixing view with business logic.
My instinct however is to use redux, and use redux-saga to manage all the side effects and complexity this way my UI is pure and is easy to write tests for. And redux-saga handles the business logic and side effect which is where they should belong anyway IMO, I want to know what the community is doing in this case.
My case, forms aren't as simple as displaying forms, and on submit, handle data, we also need to handle when something changes, we have some business logic and sometimes we actually update other values.
For things like this input is disabled when this checkbox is disabled it doesn't need redux, what about the rest? What are you guys doing?
We've integrated Redux in our project just because everyone is always talking about Redux in terms on ReactJS and we've figured out that it's a bit overhead and now complicates our code a LOT (we're using redux-observable for side effects).
Just ask yourself a single questions -
Are we going to share state between forms/pages/sections of the app?
If every form is separate and doesn't have anything to do with other parts of your application, so you don't need any kind of global state, Redux is overhead. You might want to consider structuring your app a bit better, move side-effects in your own hooks and just fully decouple your presentation from business logic - code being in useEffect, which happens to be in your component doesn't necessarily mean that it's part of UI logic, because you could easily move it in some kind of wrapper/service or later on to some kind of side-effect library (like redux-saga, redux-observable or something else).
Overall advice - don't overthink it and make it complicated, just try separating application concerns in simplest possible way and then along the road you'll start noticing what needs refactoring, code duplication which can be reused and whether or not you should introduce some kind of library that you can benefit from.
I worked on a very similar project with forms constantly resulting in side effects (fetch backend for input validation or autocomplete lists, dynamically change fields according to other field values etc.).
I used formik with the useField() hook, which allows you to read/write any field value/error anywhere inside the <Formik> tree.
Given this convenience, I wrapped the view components with logic components where the side effects are done in the logic component and just returns a view component to render. Both hooked into the fields with useField() but you might really take it to a more functional approach by passing the values/callbacks from the logic component to the view via props. This way you can easily swap out the view values with a different logic (creating a new form and editing an existing form both share the same view but use different logics).
We made a decision based on different aspects, because redux is too verbose, we didn't want to use it, but that's not how engineers choose tech.
We decided to give weights to each points:
Performance (5)
Duplication of states (5)
Ease of handling side effects (separation of concerns) (10)
Learning Curve (3)
Unit testing easeness (7)
Debugging (Dev Experience) (5)
Verbosity (less verbose is better) (5)
When we evaluated these, redux with saga came out top, sure formik has it's strength, but our whole App is just forms, and those forms aren't as simple as rendering and doing some minor side effects, it's huge form and side effects happen in such a complex ways, that just being able to track down issues using devtools is already huge.
Another thing is having a redux-saga layer helped, anyway, that's how we made the decision, but 99.9% of forms should continue using formik, but unfortunately we're at that 0.1% where redux scales with number of developers (5000+ dev in company, 50+ actively contributing to this project), and redux having devtools and ability to separate side effects, exploring data etc just made more sense.
Please choose your own when you need it.
https://github.com/reduxjs/redux/issues/1287#issuecomment-175351978 Dan says use redux if it matters globally OR is mutated in complex ways our form is mutated in such a complex ways that it's very difficult to maintain code in future, formik made it easy to write code, but redux makes it easy to debug and maintain. (for us)
I see no reason to use either redux and redux-sagas here.
You could simply use context API instead of redux. As far as redux-sagas is concerned. You could simply separate your API into different functions and keep it separately from your views.
redux-sagas are not worth it in my opinion. It is bloated and requires a learning curve about the API for the next developer. You want to keep the enterprise applications as simple as possible to keep in mind that, the next developer doesn't need to learn a bunch of APIs to edit your form. It's just a bunch of forms. Keep it simple.
Use formik and store all your state values in the localStorage on every handlePress so that it persists on refresh and on pressing the back button. Written a lot of complicated forms even with payments. Formik is literally everything you need.
And that would definitely be it. I would argue you could get away with using just formik instead of context API.
TLDR :-
It's just a bunch of forms.
It's just a bunch of API calls.
No need to overcomplicate things.
Use the native API like context or a form library.
Separate your API into an API folder.
And more importantly, store all your form values
in a cookie, if you want it to expire,
or in sessionStorage if you don't want to share data across tabs.
or just localStorage

Why can’t we use GraphQL just with Redux

I’m wondering why people doesn’t seem to use GraphQL jus with Redux.
I’ve never used GraphQL before but I’d like to start a new project, but neither Apollo and Relay doesn’t convince me. Currently I’m creating an app that use react and redux and “old fashion” rest api. And I love the idea of redux that it store whole informations about my app in one place.
And now, as far as I understand both Apollo and relay does something similar but they use separate store and in both we mixing the logic and view even more than with just React, both of these things (another store and mixing code) seems to be a bit messy. The advantage is caching, am I right?
So why can’t we just send the query as we used to with normal rest api and put the data to the redux store (maybe try to store some kind information about sync for optimisation).
Sorry if there are thing that i missed, I’m new here and I’m not a pro, it’s why I ask some people that probably has more experience that me :)
"store some kind [of] information about sync for optimisation" becomes a very hard problem when you have lot of interdependent entities.
Also, structuring the client side state is a hard problem in large applications. The rules of thumb, considered as best practices, in the redux community are that you need to normalize and remove redundancy in your redux state tree when inserting and denormalize them when using in components.
The libraries like relay and apollo want to own the state they manage so that they can remove this responsibility of normalizing/denormalizing the data, and managing the cache (as much as possible) to a significant extent from end users while still providing them low level control when they need to.
This is a fairly sophisticated problem because different components may depend on partial models eg. NoteSummary component may need only title and tags fields, the NoteDetails component will need description and comments too.
If you manage the redux state yourself you will have to write code for the following, when NoteDetails component is presented:
If a Note is not already present in the redux tree, fetch the required fields using a graphql query.
If a Note is already present, but not all the required fields are present, create a graphql query for the missing fields, and then fetch them by querying the graphql server.
If a Note is already present, and has all the required fields, just use the local version.
This becomes a lot more complex when we have entities which have dependencies on each other, or when realtime collaboration or subscriptions are involved.
GraphQL libraries attempt to solve all of the above in a very network efficient manner. Using react-apollo or relay your component can declare what all it needs and the underlying library, will intelligently figure out what and how much to fetch.
This is philosophically similar to how you write react components: In your render method you declare what your final component hierarchy should look like (given present state) and the library (react) figures out what changes are to be made to the DOM.
You should evaluate if your use case benefits from this kind of network efficiency and if so, whether you are willing to invest time putting in the effort required to learn GraphQL and the ecosystem around it.
If a redux store and a few ajax calls suffice for your use case, it can be a much simpler setup.
If you decide to go full on with GraphQL and Apollo, you might want to not have redux at all. You can use apollo-link-state and manage all your data (local or remote) using graphql Queries and mutations. Then from the perspective of your components it becomes irrelevant whether some data is remote or local.
Having said all the above, if you really want to just use redux along with graphql without any additional libraries like Relay you can use Apollo client directly. You can dispatch thunks from components, then in your thunks, you can make graphql queries directly using the Apollo client, and once you receive the response you can put that data in the tree in the tree using another action dispatch.
If this sounds more complex, it is because it simply is.

Redux actions/reducers vs. directly setting state

I'm new to Redux. I'm having trouble understanding the value of actions and reducers vs. components directly modifying the store.
In Redux, your React components don't change the store directly. Instead they dispatch an action -- sort of like publishing a message. Then a reducer handles the action -- sort of like a message subscriber -- and changes the state (more precisely, creates a new state) in response.
I feel like the pub/sub-like interaction adds layers of indirection that make it harder to understand what a component is actually doing -- why not just allow components to pass new state to the Redux store directly? Would it be a bad thing to inject something like this.props.setReduxState into a React component?
I'm starting to understand the value of why the state itself needs to be immutable (related question -- Isn't Redux just glorified global state?), related to checking for updates to see which component props need to be updated in response to state changes. My question is the extra action/reducer layers vs. manipulating the store directly.
I had some very similar questions when I decided on going down the Redux rabbit hole. In my case I was developing relatively small apps and components using just the React internal state, which still works really well. It was only when the app and the number of components grew much larger that setState became somewhat unwieldy.
I don't think this is emphasized enough - you don't always have to use Redux if you're working on a relatively small app or a few components that are easy enough to keep track of without a robust immutable store solution. There is a lot of necessary boilerplate just to get started, which can be overly time consuming in some instances.
That being said, React + Redux is a great design paradigm to follow once you are used to it and have your own boilerplate you can call upon. Redux essentially favors props over state, which forces immutable design as you (generally) can't mutate props. This is what makes the Redux DevTools "time machine" possible, along with all of the middleware that you can throw at your store as previously mentioned by others.
Middleware is a big part of it, especially with the advent of more precise solutions for sync and async tasks alike like redux-saga (https://redux-saga.js.org/). IMO "thunks" (https://github.com/gaearon/redux-thunk) are easier to grok than sagas when you're just getting started, unless you're already an expert with generators, but sagas are much more predictable and therefore testable in the long run.
So instead of having a separate internal state for each component, you can have a set of actions / reducers that you use instead, knowing that you can't mistakenly mutate the state. I've found the combination of ImmutableJS (https://facebook.github.io/immutable-js/) and Reselect (https://github.com/reactjs/reselect), which gives you composable selectors - to be great for this. No need for Object.assigns or tons of spread operators, it creates a new object for you.
I wouldn't be in a hurry to convert existing non-Redux projects into Redux, the workflow is different enough to cause significant confusion, but you'd be hard pressed to find boilerplates for new projects that don't already have Redux in their workflow. Such as "React Boilerplate" (https://github.com/react-boilerplate/react-boilerplate), I know this kind of blew my mind at first, but definitely worth getting a feel for. It really tests your functional programming chops.
In the development process, you often need to know who and how has changed the state. Mutating state by emitting actions allows you to keep answers to those questions.
Actions are payloads of information that tell the store how it should be modified. This information is represented in form of plain javascript objects which allows this information to be logged, serialized and stored. Since all the history is "remembered", you can later replay all the chain of actions for debugging or testing purposes. Together with a tool like Redux DevTools it makes development process really easy and amazing. Since all the store modifications are logged to a monitor, so you can see how and when was the state modified on every step. Even more, you can go back or forward through the actions chain.
Another benefit of having all mutations centralized in one place is the fact that it's easier to take control over the state. That guarantees, that all mutations happen one by one in a strict order and no callbacks can make the application behavior unstable. It also allows to keep in one place functionality that is common for some actions, or in other words to apply middlewares.

Resources