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

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/

Related

Why should you dispatch an action to update the state and not update the store directly in react/redux?

Explain briefly about... Why should you dispatch an action to update the state and not update the store directly in react/redux?
Redux is a dataflow pattern that is event (=action)-based. Only actions lead to store changes. Also, those have to happen without changing the old state, but by creating a new one.
This is a base assumption and un-bendable rule, because that is the purpose of Redux - moving applciation logic out of your UI layer.
All tooling depends on that assumption - e.g. react-redux will only check for new state after a dispatch and it will do so by comparing current and last state value.
If you want to directly modify it, you simply have gone for the wrong library.
There are libraries that allow for such things, like mobx or valtio, but it will not work with Redux.

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

correct react components interaction using redux

Let's suppose I have a Modal component that triggers an MODAL_CLOSE action when the user closes it.
Let's suppose I have an application that uses Modal component in many different places and, in some cases I want to change the application store when the MODAL_CLOSE event is triggered.
Is it correct to have, say a user reducer that listens for the MODAL_CLOSE action to make any change to the user portion of the store? Or by doing this I'm actually creating a coupling between the user "domain" and the Modal component?
What's the best practice in this case?
I'd say it's fine, because it's not coupling with the component, the connect call is doing the coupling.
Your reducer doesn't depend on the implementation of the component or even the existence of the component, just that there is an action MODAL_CLOSE(D?).
Likewise, your component is not coupled to or aware of the logic of the reducer.
I think it's correct. You would use something like <Modal onClose={closeModalAndDoSomethingAction} in the places where closing it has special behavior. The Modal component could then either dispatch its default onClose action, or the special one, if provided via prop. The special action would either be something other than MODAL_CLOSE or maybe have something in the payload that the reducer needs to make a distinction.

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

Angular Forms with Redux

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.)

Resources