checks inside action creators - redux

I am creating simple app, which makes GET requests to the server, then prepares recieved data and creates chart. There are few questions:
Where should I place code responsible for checking and preparing raw data. Currently I have it in my action creators, but maybe it needs to be in the component itself?
I need to check and compare prepared data with the data which is already used for the chart, and do not call re-render if it's the same or not valid. Where should I put this check? For now I think to place it inside action creators too. But for that I need to use getState() for accessing the state, doesn't look right.
Action creators seems right place for all these checks for me, because if data is not valid, I can simply not update my state with it, (e.g. do not dispatch certain action creator) Or maybe I have to update state with new data despite it is not valid?
given these action creators, what is the best place for described checks?:
export function fetchPopulations(term = "") {
return function (dispatch) {
dispatch(fetchingPopulations())
term=toTitleCase(term)
return fetch(`${API_URL}${term.replace(/\s/g, '%20')}`)
.then(response => response.json())
.then(json => dispatch(requestPopulations(json)))
}
}
export function requestPopulations(data = []) {
return {
type: REQUEST_POPULATIONS,
payload: data,
}
}
export function fetchingPopulations() {
return {
type: FETCHING_POPULATIONS
}
}

I would say you are doing it right.
In your example, requestPopulations and fetchingPopulations are the real action creators and fetchPopulations is a composing function (yes, composing functions for the win!).
Where should I place code responsible for checking and preparing raw
data. Currently I have it in my action creators, but maybe it needs
to be in the component itself?
Components are not the place for putting the business logic of our application. Components should only represent the View in our MVC. No API calls, no business logic, only props and state.
I need to check and compare prepared data with the data which is
already used for the chart, and do not call re-render if it's the same
or not valid. Where should I put this check? For now I think to place
it inside action creators too. But for that I need to use getState()
for accessing the state, doesn't look right.
Create modular functions (it really shines with code maintenance and reuse) for performing these checks, compose them together in another one along with your real action creators, and you can dispatch only if needed. Further optimization can be done inside component life cycle hook shouldComponentUpdate(nextProps, nextState). Also I think it is definitely not an anti-pattern to use methods with a signature like this:
export function myComposingFunction(params) {
return (dispatch, getState) => {
// ...
So you can use getState().
Action creators seems right place for all these checks for me, because
if data is not valid, I can simply not update my state with it, (e.g.
do not dispatch certain action creator) Or maybe I have to update
state with new data despite it is not valid?
No, do not update the state with useless data. If you do that you will re-render the entire tree for nothing. You were absolutely right to say "if data is not valid, I can simply not update my state with it, (e.g. do not dispatch certain action creator)"

Related

NgRx reducer function with condition

I have a side effect that detects the browser language and dispatches a browserLanguageSupported action if it is a language that my application can handle.
Now I have following reducer function that only updates the states preferredLanguage property in case it is not defined already. This is important because there are other actions that update this state property and I do not want a late browserLanguageSupported action to overwrite such a state update.
export interface State {
preferredLanguage: AppLanguage | undefined;
rehydrationComplete: boolean;
}
export const initialState: State = {
preferredLanguage: undefined,
rehydrationComplete: false
};
export const reducer = createReducer(
initialState,
on(LanguageActions.browserLanguageSupported, (state, {browserLanguage}) => {
if (!state.preferredLanguage) {
return {...state, preferredLanguage: browserLanguage};
}
return state;
})
);
Now for my question: Is it good practice to have such a condition in a reducer operator? The function itself is still pure. But I am not sure if it is good design or if I should solve it differently, lets say by adding state slice selection in the side effect that dispatches this action.
Btw. the reason I am not setting it directly in the initial state is because I get the browser language from an angular service and I am not sure if it is even possible to set initial feature state from service injection?
Best regards,
Pascal
I would to this the same way, so you get a đź‘Ť from me.
Adding a slice of the state into the effect just adds needless complexity.
The reducer contains the state, and it's OK to add logic to see if state needs to be updated or not.
Also, let's say you need to add this logic into another action/effect.
Having it in the reducer makes it easier to reuse if it's needed. Otherwise you end up with duplicate logic.
As long as the rejection (or mutation) of the data is irrelevant to the chain of actions & effects, this is absolutely valid.
However, it's worth noting that if the action in question triggers an effect which triggers an action, the triggered action will not know whether the data was rejected (or mutated) without checking the state—which is exactly what this pattern is attempting to avoid.
So, if you wanted to be able react to that rejection (or mutation), you would want to handle this in the effect. But, if you would proceed in exactly the same manner regardless of the result, then it belongs reducer.

What is the purpose of an actions file in Redux?

I have big problem with understand redux. The worst, I have to use it with vanillia js, but first I have to understand elements of redux. And ok, I understand reducer. There is states and functions. But action? There are only name of possible actions like:
const ADD = 'ADD'
export function add(number) {
return { type: ADD, number}
}
And only what it is given to me, that then in switch/case in reducer I have ADD I run some function (from reducer). And I don't understand what this function add should really do. I have functions in reducer, so why I need something that return me type and number? Even if I have a lot of function, action give me only more names, variables and functions and in the end big mess and problem with find something. And redux should give something opposite.
And, I really understand that problem is that I don't understand something and if I understand it redux should give me clear and understandable global storage.
So please, can someone help me with it?
What you are talking about are called "Action Creators".
They are not strictly required. It is possible for you to call dispatch directly like dispatch({ type: ADD, number}). But most people prefer to use action creators so that they can call dispatch(add(number)). It adds a layer of abstraction such that you can call an action without needing to know how the underlying action object is structured. And it simplifies things if the action object is complicated.
An "action" in redux is an object which has a type property and also has all the other information that the reducer needs to execute the action. In your case the extra information is just a number, but it could be more complex.
This is your action:
{ type: ADD, number}
An action creator is a function which takes some arguments and uses those arguments to create an action object.
This is your action creator:
export function add(number) {
return { type: ADD, number}
}
Yours is very simple, but here's an example to show you how it might be more complicated.
export function updateUser(userId, changes) {
return {
type: UPDATE_USER,
payload: {
id: userId,
changes,
},
meta: {
timestamp: Date.now(),
}
};
}
This function doesn't do anything except for create the action. It doesn't update the user -- that is the job of the reducer.
If you are wanting to reduce the amount of boilerplate, you might consider using the Redux Toolkit package, which simplifies things by creating actions automatically based on the reducer.

Redux Tutorial - why can't or shouldn't the action creator dispatch actions?

I am working my way through the redux tutorial here. I have some experience with "traditional Flux" so the first codeblock looks familiar to me, but I am confused by the second statement.
In traditional Flux, action creators often trigger a dispatch when invoked, like so:
function addTodoWithDispatch(text) {
const action = {
type: ADD_TODO,
text
}
dispatch(action)
}
In Redux this is not the case.
Instead, to actually initiate a dispatch, pass the result to the dispatch() function:
dispatch(addTodo(text))
dispatch(completeTodo(index))
If my action creator is this:
function addTodo(text) {
return {
type: ADD_TODO,
text
}
}
dispatch(addTodo(text))
Isn't that functionally equivalent to the first code example? Why does redux require the second way to actually dispatch?
Action Creators are used in Redux for adding extra layers of indirection and abstraction.
There are several reasons to use action creators rather than putting all your logic directly:
Encapsulation: Consistently using action creators means that a component doesn't have to know any of the details of creating and dispatching the action.
Abstraction: Put the logic for creating that action in one place.
Brevity: There could be some larger logic that goes into preparing the action object, rather than just immediately returning it.
Testability: It is easy to write tests for the component that pass in a mock version of the function instead. It also enables reusing the component in another situation.
Useful resources:
http://redux.js.org/docs/basics/Actions.html#action-creators
http://blog.isquaredsoftware.com/2016/10/idiomatic-redux-why-use-action-creators/

How to have multiple reducers trigger updates based on a common set of actions without repeating yourself?

I would like many different redux actions in my app to all trigger common functionality in a specific reducer. I would like to avoid having to either repeat some flag in every action creator (like doThing: true) that the reducer looks for. I also don't want to have to have the reducer just look for every individual action that falls into this category, since that also requires someone to remember to do this every time they add a new action, like adding the flag.
I was thinking of dispatching a second action every time one of these actions is going to be dispatched. This would not be hard to do, but I'd rather not have 2 actions dispatched every time one thing happens. It seems like it would pollute the state history.
Is there a common way of solving this problem?
For more context to my specific problem, the specific feature is related to the API client my app uses to talk to our API. On every successful response, we'd like to do something in a reducer to update the state, and on every failed response, we'd like to do something else.
There are many different success and failure actions (such as ITEM_FETCH_SUCCESS or WIDGET_UPDATE_FAILURE), and adding a flag to all of them would be hard to remember to do when new ones are added.
Since all api requests go through a single function, that function COULD dispatch generic REQUEST_SUCCESS and REQUEST_FAILURE actions. But this would mean every response from the server would dispatch 2 actions (REQUEST_SUCCESS and ITEM_FETCH_SUCCESS). This is obviously not ideal since it would mean many more actions in my state history.
Assuming the generic REQUEST_SUCCESS and REQUEST_FAILURE actions are updating their own specific portions of the state-tree then it is fine to dispatch them as distinct actions. Doing this does not necessarily imply the pollution of your state history but can simply be a better description of the app's intentions.
ITEM_FETCH_SUCCESS: Change state for item
REQUEST_SUCCESS: Change state for request
WIDGET_UPDATE_FAILURE: Change state for widget
REQUEST_FAILURE: Change state for request
You can see that whilst the actions are intimately related, they are not necessarily the same thing as they change different parts of the state tree.
Accepting this, the question is: How best to implement the action-pairs so that adding new actions does not mean remembering to add its corresponding REQUEST_* partner?
I would consider applying a simple redux middleware component. This could intercept the return from your api and dispatch the appropriate REQUEST_* action automatically.
Here is an example from some live code. This middleware intercepts a disconnect event raised by a websocket and automatically dispatches a custom action as a result. It at least shows the principle:
//Dispatch a disconnect action when the websocket disconnects
//This is the custom action provided by the middleware
import io from 'socket.io-client'
import { actions } from './action'
const websocket = ({ websocketUrl }) => store => {
const socket = io(websocketUrl)
socket.on('disconnect', () => store.dispatch(actions.disconnect()))
}
export default websocket
//Apply the custom middleware via the redux createStore function
//Also include the thunk middleware because it is useful
import { applyMiddleware } from 'redux'
import thunk from 'redux-thunk'
import websocket from './middleware'
function websocketize (opts) {
return createStore => (reducers, initial, enhancer) => {
const middleware = applyMiddleware(thunk, websocket(opts))
return createStore(reducers, initial, middleware)
}
}
export default websocketize
// Create the top-level redux store passing in the custom middleware enhancer
const opts = {websocketUrl: env.WEBSOCKET_URL}
const store = createStore(reducers, websocketize(opts))
This implementation keeps everything inside your reducers as opposed to having logic outside in an interception(middleware). Both ways are valid.
Try a sub-reducer pattern. I usually feel gross when I see it used(because it is usually used wrong), but your situation sounds perfect.
Extract duplicate functionality out of your reducers to one single
sub-reducer.
Then pass that reducer as a function to all others that need it.
Then pass the action and state onto the sub-reducer.
The sub-reducer does it's thing and returns that slice of state to
your parent reducer to allow you to do whatever you want with it
there (ie return it, mutate some more, some logic).
Also if you are tired of worrying about typing out "all the stuff" for async then I highly recommend you try out redux-crud.js
It also is possible and a simple way to do that would be to give every action to one reducer and let it do that common mutation, in a single case:
case actionOne
actionTwo
actionThree
actionFour: {
//do common stuff here
}
. But you said it is not duplicated, it is similar, which means your case becomes complicated by branching logic. I also don't recommend this. Keep cases simple so you can easily catch invalid mutations. This should be a super power of redux that it is easy to catch mutation errors. And for this reason and many others I don't recommend normalizing data in the front end.

How to handle cross-cutting concerns in redux reducers and actions

Given a use case like the one in this question:
Best way to update related state fields with split reducers?
What is the best practice for dealing with actions in reducers that depend on state outside of their own state? The author of the question above ended up just passing the entire state tree as a third argument to every reducer. This seems heavy-handed and risky. The Redux FAQ lists the following potential solutions:
If a reducer needs to know data from another slice of state, the state tree shape may need to be reorganized so that a single reducer is handling more of the data.
You may need to write some custom functions for handling some of these actions. This may require replacing combineReducers with your own top-level reducer function.
You can also use a utility such as reduce-reducers to run combineReducers to handle most actions, but also run a more specialized reducer for specific actions that cross state slices.
Async action creators such as redux-thunk have access to the entire state through getState(). An action creator can retrieve additional data from the state and put it in an action, so that each reducer has enough information to update its own state slice.
In my use case, I have an action "continue" that determines what page a user is allowed to go to in a multiple-form / multi-step process, and since this depends on pretty much the entire app state, I can't handle it in any of my child reducers. For now, I've pulled the store into the action creator. I use the current state of the store to calculate an action object that fires to my "page" reducer, which changes the active page. I will probably install redux-thunk and use getState() in this action creator, but I'm not committed to this approach yet.
I guess this isn't too bad of a solution since there is only one action (so far) that must be handled this way. I'm just wondering if there is a better solution, or if there is a way to re-structure my state and reducers to make it easier, or if what I'm doing is within best practices for Redux. If there are any similar examples out there, that would be helpful also.
To give some more context, my state tree currently looks like this:
{
order: order.result,
items: order.entities.items,
activePage: {
id: 'fulfillment'
// page info
},
pagesById: { // all the possible pages
fulfillment: {
id: 'fulfillment'
// page info
}
}
}
The active page is the page / section in which the user must enter data in order to proceed to the next page). Determining the active page almost always depends on the items state and sometimes depends on order state. The end result is an app where the user fills out a few forms in succession, hitting continue once the form is valid. On continue the app determines the next page needed and displays it, and so on.
EDIT: We've tried the approach of implementing a "global" reducer in combination with child reducers.
The implementation is like this...
const global = (currentState = initialState, action) => {
switch (action.type) {
default:
return currentState
}
}
const subReducers = combineReducers({
order,
meta
})
export default function (currentState = initialState, action) {
var nextState = global(currentState, action)
return subReducers(nextState, action)
}
The global reducer is first run on the whole app state, then the result of that is fed to the child reducers. I like the fact that I'm no longer putting a bunch of logic in action creators just to read different parts of state.
I believe this is in alignment with the principles of redux since every action still hits every reducer, and the order in which reducers are called is always the same. Any thoughts on this implementation?
EDIT: We are now using router libraries to handle the page state, so activePage and pagesById are gone.
If state.activePage depends of state.order and state.items, you may subscribe to the store and in case of modifications on "order" or "items" then dispatch a "checkPage" action which can set another active page if necessary. One way should to connect on a "top component" order and items, listen their values and change active page/redirect
Not easy to understand your concern, I hope my message will help. Good luck

Resources