5 ms·
Isnt Redux about using components to dispatch actions, and all the logic happens in the reducers for the store? So, the Model part is not inside the react view
by enugu 10y ago
Isnt Redux about using components to dispatch actions, and all the logic happens in the reducers for the store? So, the Model part is not inside the react view components which are just used for display. If you have uncontrolled components(React terminology for forms with extra data not handled by props), then form validation might require some processing in the components.
- WA 10y agoPartially, you're right. Some logic happen in reducers, but not all, because they must be pure. For example, you can't call new Date() in a reducer, because it's not pure. Imagine you have a TodoList with Items that have: a priority and a createdDate. TodoList is always sorted by 'priority, created DESC'. There's also an email service that gives you a high-level overview of the TodoList like so: High Prio (3 items) Mid Prio (1 item) Low Prio (0 items) Total: 4 items, last created: 2017-04-07 11:38 This email is sent out whenever a new item is added. So, your business logic is like this: If a user creates a new TodoItem: - You need to get the current date (unpure, so this must come from an action creator [1]) - You must update the "entity" of TodoList and sort and recalculate its summary - This summary must be send out as an email Or to sum it up: You have an action that triggers a bunch of totally unrelated side effects. This has nothing to do with the state of the View, which Redux manages. But it's still important business logic to this app. The question now is: How do you manage that? Because this clearly must be outside of React and Redux. Some people just slap other libraries on top, but I never found a satisfactory explanation on how to implement such workflows "properly". Too many tutorials are way too simple and gloss over these details. [1]: http://stackoverflow.com/a/34135166/ http://stackoverflow.com/a/34135166/
- BigJono 10y agoThe common solution seems to be using redux-thunk to shoehorn all of this business logic into the action creators. I think that's an absolutely terrible idea. IMO redux-thunk muddies up the terms "dispatch" and "action creator" and essentially creates a huge noob trap where new programmers don't even know what an action creator is anymore and they use the wrong terminology for everything. Having said that, I think the thunk pattern is a fantastic solution. The two things the business logic functions need to do their job are dispatch, and the state, and the way redux-thunk does it with dependency injection makes your business logic functions very easy to test. If somebody can come up with a solution with the same principle but without the absolutely moronic overloading of terms that people somehow find acceptable about redux-thunk, then they'll be onto a winner.
- WA 10y agoThanks for the input. This reflects what my problem is as a beginner with all this stuff: Where do I actually put everything? There's no universal answer of course, but this is why I (and certainly many others) feel intimidated by the JS ecosystem as a whole.
- acemarke 10y agoThe Redux FAQ has a related entry: http://redux.js.org/docs/faq/CodeStructure.html#structure-business-logic http://redux.js.org/docs/faq/CodeStructure.html#structure-bu... . Out of curiosity, could you give me some examples of what you view as "business logic", and what troubles you're having placing that into a React+Redux app? (Also worth noting that BigJono and I debated the merits of redux-thunk in another recent thread: https://news.ycombinator.com/item?id=13987613 https://news.ycombinator.com/item?id=13987613 ).
- WA 10y agoThanks for the link. Business logic, to me, is: 1. Make sure that domain rules are enforced and keep data consistent. 2. For every use case, always trigger the same sequence of actions (behavior and side effects). Imagine a fitness app where you can enter workouts and how much water you drank. You may enter only one workout per day (rule) and you cannot enter more than 1 gallon of water (rule). When you add a workout (behavior & side effects): the weather API is called and the current weather is added to the workout, the workout is stored in the DB, some calculated statistics are updated, your public "progress report card" is updated, you get a "good job!" push notification. In my PHP OOP spaghetti approach, I might create an AddWorkoutCommand that executes() these actions by calling a bunch of other functions in other objects and trigger an event for optional listeners/actions. With Redux, not everything is in the same store (or in the store at all) and I don't even know where to start. It feels like this doesn't have anything to do with Redux, because it's partially not even state/view-related. Maybe I'm overthinking this, but I do have a hard time finding a good tutorial that shows how to work with behavior and rules that goes beyond "add this item to the todo array".
- batmansmk 10y agoIt's 100% Redux ecosystem responsibility to perform the actions you want. I understand where you come from, as you perfectly described a procedure and it sounds natural to think that way. Redux and Event sourcing systems force you to decompose in 3 functions this procedure - Action creator: the action creator newTodo() creates an action = {type: 'new', body = 'yo', date: new Date()}. This action creator can be colocated in the reducer file. - Selectors: the summary is a denormalized view of the normalized state. Many would argue it is not a business logic but a display logic. Same for the sorting. A selector is a function that takes a part of the state as an input and return a new datastructure. Use reselect if you have perf concerns and want to persist it. It can be colocated code wise with the reducer file. - Saga: for the side effects of sending an email, we use Redux Saga for ol' REST based endpoints. Those can be colocated code wise with the reducer file. So yes you have 4 functions for your todo business logic: some action creators, some selectors, some sagas and the reducer. They can all be in the same file. It takes a bit of practice to figure out what is the right cut-off point. But all in all, interns and old farts like me all grasped it way more easily than Angular 1 scope concept for a more rewarding value.
- WA 10y agoThis is helpful, thank you. One note: > Selectors: the summary is a denormalized view of the normalized state. Many would argue it is not a business logic but a display logic. Same for the sorting. Yes, I read about that before. Don't put in the store what can be computed. But in my case, this isn't used in a view, but in a separate "object" that can be shared with others without sharing the underlying data. So, while the report attributes are all computed, they must be stored somewhere for later individual retrieval. Anyways, could you please clarify this: > So yes you have 4 functions for your todo business logic Where do I bundle these 4 functions so that they're called always in the same order? > It takes a bit of practice to figure out what is the right cut-off point. Yes, that's my struggle right now ;)
- lobster_johnson 10y agoRedux reducers don't manage the state of the view, but of the app. Redux state is the "M" in MVC; Redux action creators are the "C". The view's job is to display the current state, translating it into something presentable. Views call action creators to request changes to the state, or to report events that action creators should use to make changes to the state. Action creators implement business logic. Edit: To be clear, this doesn't mean you have to do logic in action creators. You can keep action creators "pure" (not thunked), and instead have a business logic layer that mediated between view and action dispatching. Saga is one way of doing this. Redux doesn't mandate anything specific. Reducers are a way to serialize the state so that all state transitions happen as a strictly sequential chain of modifications. This is done to prevent the spaghetti mess you get when (as in traditional MVC systems like Cocoa) everyone is allowed modify the state directly, and views merely observe state. By flowing state through a single bottleneck, there's only one moment when the UI needs to transition to a new state. With observation-based systems, it's completely unpredictable and certainly not reversible. React components do of course also have something called "state", but you have to think of that as the UI state, i.e. things needed to manage the view, such as whether a dropdown is open or what the current text of an input is. There's also the temptation to put UI-specific state in Redux. This is perfectly normal, and even desirable. The "M" in MVC is not some abstract ivory-tower notion that there exists some world state that's entirely independent of the view. The state serves the view; whatever the view needs must be provided by the state.