Implementing Undo with redux-saga - reactjs

If an action removeItem(itemId) is fired from the UI it should first delete the corresponding item from the state and then call the associated saga. If the saga fails it should reset the state to it's original state.
I was wondering if you can append information to the action payload within the reducers then fire a failed action from the saga with the same payload. This is assuming that the reducer will always be fired first (Is it true?)

You shouldn't dispatch from inside your reducer. A reducers job is to take current state, an action, and return new state from the reduction of the two. That's it. What you're trying to do can be accomplished by a strategy like the following:
Use itemId to get a reference to the item and store it locally.
Dispatch action to remove item from store based on id.
Call associated saga.
If it fails, add locally stored item from step 1 back into the store. If successful, remove reference to item from step 1.

Related

Custom Middleware in Redux Toolkit

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

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

CRUD Operations for list of entities in React Redux

I'm wondering what is the best way to implement CRUD operations in React Redux in case of List of entities.
Requirements:
1. Every row contain an entity
2. Changing a value in a text input trigger a PUT call to BE
3. Every row has Delete operation trigger a DELETE call to BE
4. Form has an ADD action trigger a POST call to BE
Notes:
1. No single Submit button
I thought about Redux Form for that but since I don't have a single submit operation I find it less appropriate (Feel free to correct me)
You can use Redux Form for that. If you setup a validator for the form, you can define if a field is dependent on another. Redux Form will run this validator for each change in any field.
You can setup something like Redux Observable or Redux Thunk to submit the form on Redux Form's CHANGE action when there are no validation errors in the form.
This way, you will submit the form on change, only if all the related fields are also filled.
I'm new to Redux. This is how I would do it. I will keep a state in the reducer which is called "personList". I will put all components in a container and map the personList to a property of the container called "propPersonList". When I create the ListItemComponent, I would also pass the index of the person in the list to the component as a property "propIndex". The onChange handler of the two inputs will dispatch an action with payload {index: this.props.propIndex, value: event.target.value}, then trigger a PUT request to backend (use lodash module to throttle it instead of triggering it everytime the input changes). The reducer will take care of the actions and update the state according to the payload. The add button will dispatch another action and the reducer will simply add an empty entity to the state, then trigger a request to the backend. The remove button will dispatch an action with the index as the payload, and the reducer will remove the corresponding entity from the list.

Fluxxor - how to dispatch an action in response to another?

I feel like subtitling this question "Does Fluxxor want my application to work?". No doubt however I have not grasped how to co-operate with Fluxxor...
The error is:
Cannot dispatch an action ('NEXT_AJAX_REQUEST_IS_ABOUT_TO_BE_MADE') while another action ('FIRST_AJAX_REQUEST_IS_RETURNED') is being dispatched
Component A is the owner of Component B
Component A calls an action creator in its componentWillReceiveProps. This action creator makes an AJAX request. If successful we dispatch FIRST_AJAX_REQUEST_IS_RETURNED with some data into a store. The store updates. It emits change. Component A is listening for this change. Component A updates its state. Component A re-renders passing this state as props to Component B. Component B in its componentWillReceiveProps calls an action creator to make a second AJAX request based on the data it now has. Before the actual AJAX request is made the action creator dispatches NEXT_AJAX_REQUEST_IS_ABOUT_TO_BE_MADE - in order to put a store into a certain state.
I get the message about dispatching one action while another is in progress it seems because Fluxxor does not consider the first action complete - even though I cannot have made the second until the AJAX request was completed and I have the data. The issue seems to be calling the second action from the componentWillReceiveProps method of a child component in response to changes in the owner component's state arising from the first action.
So. I tried moving the second action to the success 'callback' in the first store. I still get the same message. Even if this was the right thing to do...
The second action depends on data contained in the first action. I cannot merge these two into one single request/action and then update 2 stores using waitFor.
http://fluxxor.com/guides/react.html#batched-updates
This fixed it.
However I do not understand why and would really appreciate an explanation if anyone has it.
I think that the effect is that Component A will not re-render until state changes arising from getStateFromFlux have fully completed. So that when Component B calls its action creator we are now fully done with the first action.
Is this approximately correct?

Resources