Custom Middleware in Redux Toolkit - reactjs

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

Related

Should dispatching an action always cause a change in application state?

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/

Reducer state is not being updated with the new object [redux, redux-toolkit, normalize]

There is a DeliveryManifestView component. It runs an effect which dispatches a thunk.
The thunk gets data from the api, then it is normalized with normalizr.
The normalizedData is passed to an action created by redux-toolkit.
And the reducer returns the new object of the entity.
It works perfectly on the first run. However if I go to another view then come back
the effect re-runs, the thunk is dispatched,
the data comes from the api,
the data passed to the reducer again and the reducer returns the new data,
but no changes happen in state, I still get the old state.
Here is the action diff from redux devtools
This is on the very first render
After going back to another view and coming back
No diff in data reducer, even though a new data came from the api.
Ah - I had the same problem but turns out I was just being silly...
In my case it was the debugger. Not sure how i did it, but it was focused in on one particular part of the state, so my changes were happening but not showing in the diff. (Im using React Native Debugger)
As I say - can't figure out for the life of me how I turned it on, but I removed it by clicking on the names of other reducers that were displayed here by Diff:
The problem was that when normalizr gets an empty array it returns an undefined and so reducer returned undefined as well resulting in no changes. Here is the solution I came up with
giving a default value to the deliveryPackages.

Need to catch an action in several reducers. Anti-pattern?

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.

Initialising State in React Redux app with data in server

I am working on my first React Redux project.
The project depends on a server to get its data and therefore there is also a server API that needs to be called in order to get those data.
My question is about initialising state.
There are 2 ways I can think of initialising state:
1.) First pass an empty object {} as the initialised state of the Redux store then inside componentDidMount that is where I call the API to access the data in the server and then update the state of the store/app then.
2.) In the reducer of the Redux app call all relevant server method (e.g. getCategories(), getPosts(), etc.) then compose a object with all of the data e.g. {categories: categories, posts: posts} then pass this object to the reducer as the initial state.
Which way is the recommended way for Redux when dealing with data stored in the server?
If there is a 3rd or 4th way that is the Redux way or the recommended way then please share your knowledge. Thank you.
The way I work with data coming from the back end, and as far as I know is also the suggested way, is this:
In the componentDidMount method call a thunk action creator. you can read more about them in this link.
Inside that thunk action creator you first dispatch a REQUEST action, then perform a fetch to access the back end and when the response arrives you handle it on either the success or error handlers. Depending on the handler executed you dispatch either a SUCCESS or an ERROR action (and you attach to it all the relevant information that is coming from the back end so the reducer can access it).
In your reducer you write code to handle all the above actions (REQUEST, SUCCESS and ERROR). Each handler will transition your state, for instance the REQUEST can set an isFetching flag to true that will let you show a spinner in the UI, and the SUCCESS can set that flag to false and populate the state with the data coming from the back end and passed to the reducer using the action dispatched.
Once your reducer is updated, you will access that updated state from the UI, for instance using the connect react-redux function.
Regarding the initial state, it should represent a default state. for instance, it will have the isFetching flag in false and, if you are fetching a list of foods from the back end, then that list could be an empty list in your initial state. This is just a for instance of course. You need to set an initial state that makes sense to your app.
I hope this helps you.
The first way is the better way of initializing state. Your component makes the necessary API calls in componentDidMount and passes the data to Redux as payload of actions which the reducers use to update the state of your application.
The second way is not advisable. According to the Redux docs:
The reducer is a pure function that takes the previous state and an action, and returns the next state.
(previousState, action) => newState
...
It's very important that the reducer stays pure. Things you should never do inside a reducer:
Mutate its arguments;
Perform side effects like API calls and routing transitions;
Call non-pure functions, e.g. Date.now() or Math.random().
Edit:
You can also use thunk middleware and async actions to do API calls as explained in the Redux docs and #DiegoTArg's answer.

React-Redux: Mutating the state to emulate action side-effects with redux-undo

I have a few fields that, when updated, change the href of an image (which is really an endpoint of an external API that generates a PNG based on text input).
When that image loads, it triggers an action to update another component to match the image size (that it can only get after the image has finished loading). I set redux-undo to exclude that action from the history since it's not a user action.
Here's my problem: When I do an action that does NOT trigger a change, then undo that action, the state is wrong since the size has changed in between user actions.
An idea I had was to mutate the state (yeesh):
In reducer
case 'UPDATE_TARGET_SIZE':
/**
* HERE BE DRAGONS
* I am also mutating the current state since this action needs to
* NOT count as an user action
*/
state.targetWidth = action.targetWidth
state.targetHeight = action.targetHeight
return {
...state
}
While it works with no apparent drawbacks... it feels like a dirty hack. Is there another way of doing so or is it safe as long as I know why I'm mutating the state?
Can a lib like redux-saga help me? I admit I have not read its documentation since I am not making "real" API calls and I don't want to have an overkill solution.
Edit :
Here's a better example:
I type in a text input, which causes the href to change. A new image is loaded, which triggers the action that is excluded from the history. At that point, the history does not have the modification of that last action.
If I do an action that copies that part of the sate (in the right reducer), the state is fine. If I do an action that touches only another reducer, it will still be wrong.
So when I press undo, I undo to the wrong state. But if I get that action to mutate the state, then it's always valid.
Can a lib like redux-saga help me? I admit I have not read its
documentation since I am not making "real" API calls and I don't want
to have an overkill solution.
Redux-saga allows to perform custom side effects and introduce process manager since it has own event loop. Applying to original task, saga can help with splitting action with request and response in time.
Typical use case is emitting action with postfix _REQUEST, like LOAD_IMAGE_REQUEST, which intercepts with saga manager and does not pass into reducers. Then after async operation is done, saga emits _SUCCESS or _FAILURE-like action, dependent on sucessfullity of operation. That actions passed into store and applied with reducers.
Also, there is ideology called optimistic update. In that case _REQUEST event passed into store, but if action is failed, saga sents compensating event, which rollback optimistic action

Resources