Combine Reducers without their functional keys - reactjs

I have been working on a React / Redux Application, where now the reducer for single feature has become big enough for the thought of dividing the reducer further.
So I was thinking is there a way to divide the reducer into two different reducers and combining them without adding keys of their functional names.
For Ex:
const nowShowing = function(state = {}, action){
switch(action.type){
case types.NS_MOVIES:
return Object.assign({}, state, { nowShowingMovies: action.data })
}
const comingSoon = function(state = {}, action){
switch(action.type){
case types.CS_MOVIES:
return Object.assign({}, state, { comingSoonMovies: action.data })
}
I am looking to check if its possible to combine these reducers
const movies = combineReducers({
nowShowing,
comingSoon
})
in such a way that i can access them in the following manner
mapStateToProps(state){
nowShowing: state.movies.nowShowing,
comingSoon: state.movies.comingSoon
}
The reason i am looking for a solution like this is because, it will allow my entire application to work as earlier, but the nowShowing & comingSoon reducer become separate and my code becomes more modular.
I did try returning an object instead of combining the reducer using the combineReducers function. But that causes the entire state of the reducer to reset when there is a change in value as it recreates the object.
I think this kind of solution is not possible or it should not be attempted. But I would to understand more why, as I do agree that this points to more over architectural flaw in constructing the reducers in the first place.
Any help would be highly appreciated.
Thanks

Related

react redux not displaying the correct data

i've taken a few courses on react and redux and so far the challenges are still piling up. i'm creating a simple app were at the time i need to just map the response from the api, but the state looks weird. the actions is returning the data, but is being displayed awkward. Please see the images attached. Does anyone know why the console.log of the data returns a number instead of an object or array name? also if you see the state from the redux dev tools, you can see that where an object name would be displayed, you see undefined instead. Please help. I've been at it for a couple of days and have been banging my head against the wall. enter image description here
reducer
import _ from 'lodash';
import {
FETCH_CLIENT,
FETCH_CLIENTS,
ADD_CLIENTS_COMMENTS
} from "../actions/types";
export default (state = {}, action) => {
switch (action.type) {
case FETCH_CLIENT:
return { ...state, ..._.mapKeys(action.payload, 'ClientUno') };
case FETCH_CLIENTS:
return { ...state, [action.payload.ClientUno]: action.payload };
case ADD_CLIENTS_COMMENTS:
return { ...state, [action.payload.ClientUno]: action.payload };
default:
return state;
}
};
combined reducer
import { combineReducers } from "redux";
import ClientsReducer from "./ClientsReducer";
export default combineReducers({
clients:ClientsReducer
});
action
const mapStateToProps = state => {
return{
clients:Object.values(state.clients),
}
}
export default connect(mapStateToProps,{fetchAllClients})(Clients);
after removing .ClientUno. This my new state
post man response attached
It looks like your reducer logic is wrong:
return { ...state, [action.payload.ClientUno]: action.payload }
Per the screenshots, your action.payload is an array of items. The individual items do have a .ClientUno field inside them. But the array most definitely will not. So, action.payload.ClientUno is indeed undefined, and that's what you're using as a key.
You'll need to rethink what you want to use as a key there. I don't know how you're actually trying to structure this slice state, so I can't provide a suggestion there.
I will note that the Redux patterns you're using here are very outdated. "Modern Redux" with Redux Toolkit is much simpler and easier to use - there's no "ACTION_TYPES", switch statements, or object spreads. Please see our official Redux docs tutorials to learn how to use Redux Toolkit:
https://redux.js.org/tutorials/index

fundamental redux concept- how to actions launch reducers

to make things simple consider these two reducers(written in typescript):
export type userActionTypes =
| Interface1
| Interface2
const initialState1 = {...//some state} //<--comment indicates some sort of values are present
const initialState2 = {...//some state}
const reducer1 = (state = initialState1, action: userActionTypes){
switch(action.type) {
case action1.case1:
return {...//some new state1}
default: return state
}
}
const reducer2 = (state = initialState2, action: userActionTypes){
switch(action.type){
case action2.case2:
return {...//some new state1}
default: return state
}
}
const rootReducer = combineReducers({
mReducer1: reducer1,
mReducer2: reducer2
})
now say somewhere we call the following in our code:
newAction = {type: action2.type2, //some other values}
dispatch(newAction);
**my question is: ** How does react know which reducer to call? I mean, it doesn't pass the action to every reducer there is in the rootReducer, does it? I mean if that was the case, then all the default cases would be meaningless and all the cases in the case statements would have to be unique. That is not possible, is it?
How does react know which reducer to call?
How does react know which reducer to call? I mean, it doesn't pass the
action to every reducer there is in the rootReducer, does it?
Trick question, redux actually calls all of your reducers.
Consider your root reducer:
const rootReducer = combineReducers({
mReducer1: reducer1,
mReducer2: reducer2
})
This creates a reducer function tree. When an action is dispatched to the store it calls the root reducer and passes the current state and the current action. The reducers in turn recursively call their nested combined reducers, passing state and action until they reach a leaf where you hit a reducer function and compute their next state. They either have a case to handle action or the return the default case which is simply their current state. The recursion goes back up, returning each next state slice piece, combined at each level until you arrive back at the root reducer which returns the entire next state object.
I mean if that was the case, then all the default cases would be
meaningless and all the cases in the case statements would have to be
unique. That is not possible, is it?
Remember that each reducer function is operating on only its little slice of state, not the entire state object. The default case is there for the reducer to return its current state value since there is no work for it to do. All the reducer cases within a reducer function should be unique. If two actions trigger the same state update then they should be grouped
case "case1":
case "case13":
// both cases apply the same update

React redux-strange behavior, prevState and newState change together

I started to work on some frontend project, I needed to plant foundation and I choosed to go with react and redux. I went through some tutorials and started to build my project.
Everything was working fine, but all of sudden I m stuck with problem I'm not even sure how to describe it.
Problem is connected with using redux, reducers.
In short somehow my prevState was changing with the newState. The worst part is I cant share much more information, I'm new to this react/redux, so I'm not even sure if this is even possible.
Here is the example code:
export default function (state: UserReducerState = initialState, action: Action): any {
const newState = Object.assign({}, state);
console.log(state);
state.loginStatus.username="This change should only be on prevState";
console.log("newState",newState);
return newState;
};
When I console.log(newState) it has the change from the old state even though the newState was copied before the state.loginStatus.username ="This change......."
I dont know what code should I show more, but this is where problem start,I think.
How is even possible that object that is copied have the refrence to the old one ?
Issue
Even though you are copying the state object it isn't a deep copy. You are mutating the more deeply nested properties of your previous state object since the new state is simply holding a reference to them.
state.loginStatus.username = "This change should only be on prevState";
newState is a new object, but newState.loginStatus.username is reference back to the same object the previous state holds.
Solution
I'm not sure why you'd mutate your old state object in a reducer, but when updating the more deeply nested properties in the new state you must shallow copy any nested state that is being updated. Typically this is achieved via the spread syntax.
export default function (state: UserReducerState = initialState, action: Action): any {
const newState = {
...state,
loginStatus: {
...state.loginStatus,
username: "This change should only be on newState".
},
};
console.log(state);
console.log("newState", newState);
return newState;
};

Redux, when to split reducers?

I have a Redux store with a reducer consisting of 9 case statements. Six of these cases deal with populating an array in the state white three deal with sorting said array, thus there is no natural way of splitting the reducer, is it ok to leave the reducer as one?
The number of case statements isn't the right metric for deciding whether you should split your reducer. Rather, it's how deeply nested is the state slice that your reducer action handler is working on. If its too deep, the code could explode.
Lets say you have this state shape:
{
cart: {
products: [ {name:"shirt"}, {name:"pants"} ],
checkout: false,
}
}
In a single/global reducer setup, you might have this action handler:
//reducer.js
case ADD_CART_PRODUCT:
const {newProduct} = payload
const {cart: {products}} = state
return {...state, cart: {...state.cart, products: [...products, newProduct] } }
Not bad, but you can split off a cartReducer for action handlers that affects the cart state slice, shrinking your code to this:
//cartReducer.js
case ADD_CART_PRODUCT:
const {newProduct} = payload
const {products} = state //this is actually state.cart from the global perspective
return {...state, products: [...products, newProduct] } }
Yes, it is okay to leave the reducer as one. Lets say if I have a reducer for User, I would consider splitting the reducer if it got too big to manage or if it had nothing to do with User and that was my first one. You only have 9 switch cases and that should be fine.

In Redux, is it necessary to do deep copy

The below object is action.data has a nested object address
{
name: 'Ben',
address: {
country: 'Australia',
state: 'NSW'
}
}
How should I handle it in the reducer?
const rootReducer = (state = initState, action) {
switch(action.type) {
switch RECEIVE_DATA:
return {...state, data: action.data}
}
}
Can I do it as above? that I just assign the whole object to data without copying?
or
const rootReducer = (state = initState, action) {
switch(action.type) {
switch RECEIVE_DATA:
const address = {...action.data.address}
const data = {...action.data, address}
return {...state, data}
}
}
Or should I do a deep copy of the object and assign it to data?
thanks
The "correct" way to handle updates of nested data is with multiple shallow copies, one for each level of nesting. It's also certainly okay to create a new object that just replaces one field completely, per your first example.
See the Redux docs section on Immutable Update Patterns for some info on how to properly do immutable updates, and also the Redux FAQ entry regarding deep cloning.
From Redux:
Common Redux misconception: you need to deeply clone the state. Reality: if something inside doesn't change, keep its reference the same!
No, shallow copy of Unchanged properties.Changed properties will be anyway new values, so no question of type of copy.
In code we achieve it like this return {...prevState}
If you are changing only one item in an array, Redux docs says you can use array.map, but if you know the index, this is faster:
state[action.args.index] = {
...state[action.args.index],
disregardLeafNode: action.args.checked
}
return state

Resources