I'm working on re-writing/porting my huge slideshow project to React and Redux, which used to be a big jQuery project with business logic stored in large classes.
I'm going to dive straight into my problem.
I have three Redux reducers, actions and middlewares:
Feeds
Moderation
Slideshow
The feeds middleware takes care of fetching new posts, and storing them in feed.posts
The slideshow reducer maintains a lot of state about the slideshow itself, and business logic, e.g. which post it's currently displaying, what post should come next in, etc. It should also maintain a list of posts that have been filtered, e.g. there should be no posts that have been blocked.
The problem I'm facing is this:
The feeds middleware dispatches an action with new posts, and then the feeds reducer stores the posts in feed.posts. That's all fine. But now I want the slideshow reducer to process the posts, to remove posts that have been blocked, etc, and then store them under slideshow.posts, while the feeds.posts will always contain the raw post list for other purposes.
My current solution basically to catch the new posts action in the slideshow middleware, and from there I dispatch a new action with the new posts, which can then be processed in the slideshow reducer. This feels anti-pattern; using a middleware to dispatch an action so that it can be processed in a different reducer.
Another solution would be to dispatch two actions in the feeds middleware when new posts are available:
dispatch(feedNewPosts(posts))
dispatch(slideshowNewPosts(posts))
This way I can get rid of the middleware hack, but it also feels anti-pattern.
Then I thought about using selectors, the slideshow container would select the posts and filter them by the blocked list, etc. But the problem I'm facing with that solution is that I need to know which posts have been blocked in the slideshow reducer because most of the business logic for the slideshow happens in there.
Here's an example:
The slideshow middleware dispatches an action to show the next slide, dispatch(slideshowNextSlide()).
The slideshow reducer handles the action and checks which slide should be displayed next, and stores that slide in the state as slideshow.nextSlide, add flags to the post for animation purposes, etc. So based on that, I need access to the filtered posts in the slideshow reducer.
So if this was all handled by complex selectors, then I won't have all the information I need in the state, e.g. which slide should come next, so that I can add the correct animation classes, etc.
Is there something obvious I'm missing? Perhaps I'm trying to have too much information stored in the state, but I love the idea of having the complete state of the slideshow in the state, e.g. if I want to save the slideshow state and load it later, etc.
The slideshow container and component would be really dumb, just display whatever is in the state, add certain animation classes if the post matches slideshow.nextSlide and so on. No complex selectors.
Any help in the right direction would be highly appreciated.
Thanks.
It is perfectly fine for two reducers to listen to the same action. That is one of the benefits of redux: A certain event happening on your application might be interesting for more than one component, and you don't want them to be aware of others.
So triggering a second action would be an anti-pattern. I would aim to raise a single action:
dispatch(newPosts(posts))
and then you could have both the feed and the slideshow reducer listening to the same action, and modifying their part of their state accordingly.
I think in this case it is important to separate the abstract action that is happening in your system (new posts are available based on the result of an API call or something else) from the reducers that are going to listen to it. If you do that, having one action that modifies two different slices of the state feels much more natural.
Related
This is more of a best practice question. I'm thinking about a piece of code I observed in a reducer, where it went like this:
if (!state.arrayOfObjects) return;
else {/** add an object to the array of objects/}
Intuitively, I think of an action as something that occurred which enacts some change on the application state. If dispatching an action causes no state change, then I feel that the action most likely should not have been dispatched at all. If there is some condition within the reducer which prevents change from occurring, it probably should have been a condition for the dispatch of the action itself.
On the other hand, maybe the condition within a reducer is one way to create a condition based on a property you don't necessarily want a component to be subscribed to. However, I would think that if the specific action depends on that property, it would be odd for the component to not need the most recent value of that property via subscription in order to determine whether or not it should be dispatched.
In Redux, any number or reducers can react to any action. That includes 0 reducers and 50 reducers.
The Redux Style Guide encourages to Model Actions as Events, Not Setters and to Put as Much Logic as Possible in Reducers.
So while it might not be the common case, it is perfectly fine to have actions that no reducer or middleware reacts to ever - for example for logging puposes or because a reducer might use it in the future. Having actions that reducers react to sometimes, based on some logic, is perfectly normal and 100% fine.
There is a really good article for this question since I can't quiet explain the answer myself. http://jamesknelson.com/join-the-dark-side-of-the-flux-responding-to-actions-with-actors/
I have created a Reducer with createSlice and want to reset|modify the state of this slice every time a dispatch matches one of the cases of the reducer.
Specifically, I want to have an ErrorSlice (ErrorReducer) which is reset before each request, so old errors are deleted and only new errors are displayed. I could probably reset the state in each of the cases but i would like to solve this for all cases in one place
I've seen numerous examples about this, but every example incorporates details about persistent values like todo is "completed".
I understand we should keep this ("completed") value in store for each TODO, and when store gets recomputed using reducers, the component is re-rendered.
Where do we keep information like "isUpdating" etc for each todo, which I would use to show a loader on a particular todo item (not for the list of todos) when user marks a todo complete and a subsequent ajax call is involved to mark todo as complete in database.
I also understand that as this information might not be useful for other components I should better keep it under the presentational component "TODO". But if these flags are kept in the component, how will the component know that the update on todo was successful or failure on store update ?
In redux we have multiple reducers that handle state as whole. In a todo app, todos are a slice of the state, but they are not always the entire state. In your case, your app's state consists of two entities, the todos, and the status of the loading.
With the above in mind, you can have one reducer that handles the todods. It will take care of loading all the items, or updating an item, or deleting one. In other words, this reducer is only concerned with the state of the todos, but it does not care about where you are in your lading process of an ajax call.
For the loading process you can create another reducer. This reducer knows nothing about your todos and it can really work for any sort of data that your app manages. All this reducer is worried about is if we are currently in the middle of an async ajax call. If we are then we can set some bool like isLoadingto true, and when the async call is either done or errored out we just set it to false. Then any component that wants to display some spinner while loading only needs to subscribe to state changes of this loading reducer.
This is the way I have implemented this feature in multiple production projects at my work. This is by no means the only way, or the best way, its just a way that I know works.
EDIT: The above works well for a more general loader across the site, however the OP wants to know how to make each individual item show a loader when some async call is happening that involves only that item.
The approach I would take is as follows. Instead of having only one array in state that keeps track of the todos, we now have 2 arrays in state. One array keeps track of the data, and the other keeps track of the data as it relates to UI. In other words, the array that keeps track of data will know nothing about isLoading since this is a UI related prop, but the other array will keep track of all the todos as they relate to UI. This way when looping through each todo during the render faze, we can look to see what the isLoading status is of this exact todo in the UI related array in state, and if isLoading is true then we display a spinner on this specific todo.
This gives a nice seperation of concerns. The array that is keeping track of data does not need to worry about UI at all. but we still get the benefit of having an individual spinner for item in the list.
If you want to use redux middleware for handling these asynchronous action (such as redux-saga that you have tagged your question with) then it is much easier to store the values alongside the relevant items in the state.
Basically, it boils down to this: If you've externalised the action from the component, then you should externalise the resulting state of the action.
Looking for some advice when working with Redux, and Angular. I've been researching Redux for the past couple of days and really think its a great way to store application data. The part I'm having trouble with is whether to persist everything within the store or only certain parts. Ideally, I think the entire application should be running through the store, but for forms this seems very tedious.
For example, lets say I'm working with a form to add a new product. Here are some of my pain points.
I would like to keep the User Reducer (store) separated from the actual form state. Should I create a separate form reducer per component?
Having to persist every input field back to the store sounds like a lot of work. I've seen the library redux-form simplifies this, but is intended for React.
Anyone have any good advice when it comes to creating forms in Angular with Redux?
The answer is "it depends". Also, the assumption is that you''re convinced of the benefits of one-way data flow and redux, so prefer redux over two-way data binding if given the choice.
Uber-simple form (no validation, no complex relationships with other state). Then you could "go naked" and directly hook up the inputs to redux. In our use case, we actually decided to go with Angular forms because we figured it handles edge cases (IE and safari mobile).
Don't need every form change in redux state. Then the form submit can dispatch an action to update redux state. Things get tricky if the form needs to change in response to redux state. See below.
You do need every form change in redux state. Angular forms do not have a form#ng-change, so one strategy is to attach an ng-change to every input that dispatches an action to update the redux state. (Yes, it is error prone because it easy to forget to use ng-change, meanwhile the app appears to work.) Again, things get tricky if the form needs to change in response to redux state. See below.
Updating the form in response to redux state change
The common use case is actually very simple. A concrete example will help---suppose the form tracks app settings, meanwhile app settings exist as redux state. That is, there is a two-way data binding between the Angular form and the redux state. This is probably the common use case.
In this case, the solution is to proceed as before: update redux state from the Angular form by dispatching update actions, and update the Angular form from redux state via #mapStateToThis.
Angular ----dispatch actions-----> Redux
Form <----mapStateToThis-------- State
The only gotcha is to not pass the Redux state directly to the Angular form i.e., deep clone the data or use ImmutableJS.
The other common use case is to implement a "form reset", that is, reset the form to a "pristine" state after pressing a button, for example. Again, a concrete example will help:
Suppose that app state (redux state) tracks whether the state is pristine via a flag app.pristine. (To clarify how app.pristine works, it works as expected, that is, it changes to false as soon as any value changes, and changes to true only when explicitly set to true.)
First, as far as I know, Angular doesn't automagically keep track of the "initial" state. You have to do it yourself and you may as well put that state in redux. Then, the initial form values are just the app settings when app.pristine is false. (If you're thinking of putting this in #mapStateToThis, don't. Doing side effects in a transform function seems weird.) A better way is to use an asynchronous action, namely the form onChange listener:
// thunk example
onFormChange(newForm) {
return (dispatch, getState) => {
const appSettings = getState().appSettings;
const appIsPristine = appSettings.pristine;
// this will fire once because the next action will set it to false
appIsPristine && dispatch(initForm(appSettings)));
dispatch(updateAppSettings(newForm));
};
},
The reset action works as you would expect (which I won't outline).
To conclude, I should add that the above assumes that only the Angular form can dirty the app settings---otherwise, the initial form values may never be stored. If that's the case, then one idiomatic solution is to create a custom middleware that sets the initial form value whenever app.pristine changes to true. (Alternatively, use an Angular watch.)
My app has one store with multiple reducers as it is a single page app so each "page" has its own reducers. Problem is, I am creating a redis api so that a user can "save" state. When a user refreshes, I need to ping redis and there is data, funnel it thru the reducers to now update the state.
So, if I have a few reducers to manage different parts of the store, what is the best way or even how, and where ( parent component ) to bring in this redis data and then push it thru the reducers, my guess is that I would have to call the actions - as then they would call the reducers..
/actions
----> productsActions
----> userDataActions
----> deliveryActions
/reducers
----> productsReducer
----> userDataReucer
----> deliveryReducer
Application
---> Routes
------> Child Routes for products/data/delivery
When a user refreshes, my store is gone. I want now retrieve that data and update the store/state all in one fell swoop, as I have a cart that when opened shows all the data, and that is a seperate component.
I hope I explained succinctly. I am really just having a hard time grasping how this would be done.
edit: ok, so - I am thinking each reducer has its own "default" state, perhaps on page load, grab the redis data and update theses default states. This way I do not have to call the actions?
edite 2: If that is the case, is there a redux api that handles conditions in which fetching the data takes longer than the page to load, which case I would need the reducers to be instantiated again so they pick up the "new default states"..
Sounds like you are trying to rehydrate your stores. You might want to check out redux-persist as it does most of what I think you want.