I am wondering what is the best design approach between using a big state (store) and sql request in database.
Let's say you have a Todo CRUD application. You can save the Todos list in store within Redux implementation. What is the best approach if you want to make complex statistics on those TODOs: Reducers or sql requests?
For example, you want to get all todos for the current month:
Reducers/store approach
You can get all the todos list from the store and filter todos by date to get all todos for the current month.
Pros:
CRUD actions easy to manage, one state changes in the store (todos list)
Low client/server traffics
Cons
Business logic on client side
client overhead for large data processing
Sql request approach:
Complex request in database to get those todos and save the state 'currentMonthTodos' in the store. In this case you get your current month Todos list from currentMonthTodos state
Pros:
Business logic on server side
Reducing page load time for large datas
Cons
Poor state management for CRUD actions
High network traffic
Size of the store grows up
Let's say you have a Todo CRUD application. You can save the Todos list in store within Redux implementation. What is the best approach if you want to make complex statistics on those TODOs: Reducers or sql requests?
Usually, real life applications you do with the Redux are medium or large scale. Simple CRUD applications you could do either way.
I guess when you mentioned the database (SQL requests) you considered Restful programming.
For the very simple applications, the Redux pattern doesn't have that much sense, unless you need advanced visual effects.
However, small applications do grow over time and can become medium scale fast, by adding more components.
Redux idea is excellent in cases we have a great number of application components that interact. In Redux these will be called the container components, and these are different from the simple presentational components that are also known as stateless functional components.
Having 2 components A and B you have just a few possible update chains.
A will update B and B will update A, or self-update (not including in here the possible updates from outside of the app).
With just three components interacting we have much more possible chains.
And with even more components it gets complicated. We eliminate the possible exponential interaction complexity with the Redux pattern. Redux pattern is similar to IDispatch, IObservable if you worked with these interfaces from some other programming languages.
One would be for spitting the actions, and the other for entering the listener's chain that exists inside the store.
We get very similar to the event driven approach in GUI applications — when you move the mouse you get the events.
In React components create actions. Sometimes a lot of actions. In fact, you may get so many actions in some cases so the application will freeze if you have the bad design.
Typically components should throttle the actions and there are great solutions in React for that.
So what are components in React Redux? From one side components are action dispatcher and on the another side they get the props, possible context, possible the application state or even local state. Finally, components may have the rendering logic. Sometimes components are just containers.
I just wrote this to represent the initial complexity of the Redux pattern while Restful applications are by design simple.
I think that this is the main factor you should take into account. Using Redux for the trivial TODO applications that will never grow the complexity may not be needed, so you may go with the Restful app.
https://egghead.io/lessons/javascript-redux-store-methods-getstate-dispatch-and-subscribe?course=getting-started-with-redux
Related
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.
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
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.
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.
Let's say I have some data tables, like a list an admin report returning a list of users (with details) or a list of log records. Does this info belong in the redux store, where only the data table needs this info? Or what if I am plotting something with 5000 nodes. Does this belong in redux single app state too? Why or why not?
If these items do not belong in the app state, is it just the local component state I should be loading these into without redux? Seems nice to have all my async requests fetched similarly, though.
Since redux doesn't care about the data (it literally just calls reducer functions when actions are dispatched, and replaces the current state with the result), there shouldn't be any performance issue there. It will be as performant as the reducer functions you provide.
If you'd like to see for this directly: https://github.com/rackt/redux/blob/master/src/createStore.js#L115
You're more likely to run into performance issues with react, but even then its doubtful at that scale. You may want to virtualize your table so that you're not rendering out of view elements, but that's a common problem with ui programming.
Yes, the Redux way is to put all your client-side state in the Redux store. See the Three Principles of Redux, the first one in particular:
Single source of truth
The state of your whole application is stored in an object tree within a single store.
This makes it easy to create universal apps, as the state from your server can be serialized and hydrated into the client with no extra coding effort. A single state tree also makes it easier to debug or introspect an application; it also enables you to persist your app’s state in development, for a faster development cycle. Some functionality which has been traditionally difficult to implement - Undo/Redo, for example - can suddenly become trivial to implement, if all of your state is stored in a single tree.