I would like to dispatch an action after a first one has been processed by the reducers.
Here is my use case. My component allows the user to select a list of notes (this list is store in redux). Based on some user actions, a random note can be selected from this list and saved in the store.
In the screenshot you can see buttons. "Select All" and "Unselect All" act on the list of possible note. "Start" pick a note from the list.
The issue I have concern the "reset button". It is supposed to chain "select all" and "start" and I don't know how to do that. I tried a naive:
const reset = function () {
dispatch(selectAll());
dispatch(pickANote());
}
With this example, I am facing what I think is a data race. The second action pick a note from a note updated list.
Digging the internet, I found only cases of action chaining based on API calls with redux thunk. The problem I have is that I don't know how to trigger something when a action is processed (which is obvious with an API call)
So, there is 3 solutions:
I am missing something obvious
I am going where no man has gone before
I am doing something anti-pattern
Any help is welcome.
Alright, I found my answer.
No surprise, I was thinking anti-pattern.
In the redux style guide, there is 2 points that lead me to the solution.
It is strongly recommended to dispatch one action that is processed
by several reducers.
It is strongly recommended to put the logic inside the reducers.
The consequence is that I should dispatch "raw data" and then compute value reducers. Following this path, I am not dependent on the values already in the store for the next updates and so, I do not face any data race.
Related
I'm using #reduxjs/toolkit createSlice feature for the whole application.
I often have a need to access other slices's state. One common example is for the "one to many relationship" where children are stored in normalized form by "byParentId" key in their respective state. So, when user makes some "parent" active, almost every selector / reducer / saga effect in the "child" needs access to "parent" state "active" field. Initially, I simply added "activeParent" field to the action while combining reducers. Later on, with more such cases I ended up with just "global" variable in action with the whole state for every action instead of crafting data preparation in the combine reducers function.
This also improved performance in redux-saga, where yield select(selector) calls where replaced with synchronous selector(global)
Here #gaeron claims this approach to be an anti-pattern, which can be usually solved by:
Removing that logic from reducer and moving it to a selector
Good, when possible.
Passing additional information into the action;
Sometimes it is good, but often introduces unnecessary performance hit.
To pass additional information to an action it should be retrieved by useSelector into component which may otherwise don't need it, read: more redraws.
Letting the view code perform two actions.
Again, good, but not always. It requires to put sequences of actions in multiple components instead of having a simple logic,
when one action results in another one.
One mentioned problem:
reducers become coupled to each other’s state shape which complicates any refactoring or change in the state structure.
can be easily avoided by using selectors instead of accessing "foreign" state directly.
Is there a real reason for this approach to be anti-pattern?
Putting the entire root state into an action is definitely an anti-pattern and should be avoided.
You may want to sometimes put additional data from the state into specific actions if the reducer logic needs it.
Beyond that, I'd need to see more specific details on what you're trying to do and what the code looks like to offer additional advice.
Each big components get its own list of actions. Separation of files implies that they are isolate actions. But from my understanding if a type of an action matches the type of another action in completely separate file meant for different reducer will still cause problem.
EDIT:
if i have two sections in the app. One has reducer for action SET_SCROLL, and other section has that too. If i update scroll position in section 2, by firing SET_SCROLL. This would cause section 1's state to change. Now imagine 100s of actions, how do you prevent naming conflicts? I understand in redux you can't associate set of actions with a certain reducers.
Yes, this is why you should be careful when defining action types. The "Reusing Reducer Logic" docs page gives examples of how this can be a problem when you want to reuse a given reducer in more than one place, and shows some ways around that.
We specifically recommend defining action types as "domain/someAction" to help avoid clashes.
Note that it's also possible (and recommended) to have many different parts of the reducer logic all independently respond to the same dispatched action
I have a app in which users can build a "Quote". So far I've been adhering to "idiomatic" redux (or something close to it) and it's been working out well.
However, I'm struggling to deal with a fairly simple scenario:
When the page is first opened, I fire an async LOAD event which retrieves info from the server needed to build the quote (products, inventory, previously saved line items, etc).
I need some way to be able to automatically add a specific line item(s) to the quote first it's first opened.
I've added a defaultLineItems property to my LOAD payload, but to fire the addLineItem(product, inventory, options) action, I need data from the productReducer, inventoryReducer, optionsReducer. The lineItemReducer could look at these defaultLineItems and try to set it's state appropriately, but that would require having to rewrite a lot of BL typically handled by the actions using data aggregated from reducer memorized "selectors" (EG: defaulting price, quantity, currency translation, etc)
I can think of a couple ways to achieve this, but they all seem somewhat hack-ish (IE storing a flag in the reducer that says I need to fire an action and then running it when my root component props update). It seems like a react component should not be responsible for this type thing.
What is the proper way to do something like this?
Seems there are a couple different ways this can be accomplished but for me the most balanced approach between simplicity and design was to use store.subscribe in conjunction with a reducer to track the last action(s).
At it's simplest, this would look something like this.
store.subscribe(function() {
let state = store.getState();
if(state.lastAction.type === ActionKeys.LOAD){
console.log('load action fired!');
}
})
Please be aware that firing an action from store.subscribe will cause recursion so you need to be selective.
I am using same filter two time same screen for different purpose. Now updating at one place automatically updates the dependent values on second filter as well.
You are going to need two states in your Redux store - one for each filter. Then you need to connect one state to one filter, and the other state to the other filter.
You don't need to duplicate your reducers and actions though. Your action could take an filterId as input, and then pass this down to the reducer. The reducer updates different states based on which filterId is passed in from the action.
Hope that makes sense! Feel free to add follow up questions or additional information about your problem to get a more detailed explanation!
I'm developing an application that has several states (reducers). Let's say they are messages, likes, comments (all of them are from the completely different instances so i'm not sure if i should combine them into one state).
Every 30 seconds i make request to the server and i receive response that says which parts of my application have been updated. E.g. i received new messages or new comment.
I don't really know how to handle those responses. First, i can simply let container update all other states, but i don't think that it's a good idea, because every container should have it's own state.
Second, i can create a middleware that will catch every action, find the one with required information and shot another action (e.g. new message). After that reducer of the messages will catch this action. But i'm not sure again if this is a correct approach for two reasons:
Is it okay to shot actions from the middleware (won't it be a bidirectional flow)?
How can i actually do it?
Thanks in advance.
UPD. I did it using middleware, but i'm still not sure if this is a correct way. In my middleware i obtain required data using store.getState()... and then i make store.dispatch(myAction). Is it okay?
It's important to understand that a reducer /= state. ( reducer not equal state )
You should have one state, one store for your application. Use combineReducers to well.. combine reducers to keep everything in one state.
http://redux.js.org/docs/api/combineReducers.html
You need to handle async behaviour, something which is not default by redux and therefore you have to use some kind of middleware - meaning you were on the right track.
Try and use the more common once like:
https://github.com/gaearon/redux-thunk
https://github.com/redux-saga/redux-saga
It's advised to separate the async logic from your app. Meaning you need to init your async calling in the app, but keep the async logic in the store.
Here's a guide by Dan Abramov and Redux-Thunk which is simple and clear:
http://redux.js.org/docs/advanced/AsyncActions.html
Hope it answers you.