how to update a specific property in a state using ngrx - ngrx

how do i update a specific property of object in a state?
i need to update the property offerPrice but still want to retain the other state values in the object
this is what i have in my effects
case OffersActionTypes.SET_TOTAL_OFFER_PRICE:
return {
...state, offerDetails: {
...state, singleOfferDetails: [
...state.offerPrice, action.payload
]
}}
but on the redux tools it giving me this

If you look carefully, you're not copying the parts of state that need to be copied. I believe you want something more like:
return {
...state,
offerDetails: {
...state.offerDetails,
singleOfferDetails: {
...state.offerDetails.singleOfferDetails,
offerPrice: action.payload
}
}
}
Of course, this can also be achieved with something like:
const newState = { ...state };
newState.offerDetails.singleOfferDetails.offerPrice = action.payload;
return newState;
I would argue, however, that your store is too embedded. Generally you want to keep things as flat as possible, although I'll grant you that it's not always a simple process. Best of luck!

Related

Redux reducer design for large state within a single module

I have come across two kinds of reducer design for handling a large state within a single module.
The first approach is to have all the variables inside a single large state and have one reducer function.
const initialState = {
results: [],
pagination: {},
filters: [],
appliedFilters = [],
}
const reducer = (st = { ...initialState }, action) => {
const state = st;
switch (action.type) {
case 'SEARCH':{
return {
...state,
results: action.results,
pagination: action.pagination,
filters: action.filters,
appliedFilters: action.appliedFilters
},
case 'APPLY_FILTER':{
return {
...state,
results: action.results,
pagination: action.pagination,
filters: action.filters,
appliedFilters: action.appliedFilters
},
case 'PAGINATE':{
return {
...state,
results: action.results,
pagination: action.pagination,
}
}
The second approach is to have multiple reducers for the sub items in the data.
export function applications(state = [], { type, results}) {
switch (type) {
case SEARCH:
return results;
case INIT_RESULTS:
return [];
default:
return state;
}
}
export function pagination(state = null, { type, paginationData }) {
switch (type) {
case SEARCH:
return paginationData;
default:
return state;
}
}
export function filters(state = [], { type, filterData }) {
switch (type) {
case SEARCH:
return filterData;
case UPDATE_FILTERS:
return filterData;
default:
return state;
}
}
I think both have their own pros and cons. Considering scalability and modularization which one is a better pick?
Generally, both of these are very far off our official recommendations.
you should have a "slice" reducer for each sub-state (that rules out your first option
you should not treat reducers as "setting a value", but move the whole "calculating how to get the value" into the reducer and handle your action as just "describing an event that happened"
you should be using the official Redux Toolkit which we are recommending & teaching as the default way of writing Redux sinde 2019. Seriously, look at it. It is about 1/4 of the code. No more switch..case reducers or ACTION_TYPES.
Please give the Redux Style Guide a read and to learn modern Redux with Redux Toolkit, please follow the official Redux Tutorial

Redux state is being overwritten by other state change

I am new to redux and I was testing it by creating a theme toggler and a counter.
the problem is everytime i click to increment the counter that works fine but when i try to toggle the dark theme the count resets to 0 and vice versa. I am using combineReducers which holds the themeReducer and counterReducer.
Why is the counter getting reset on state change? what am i doing wrong?
here is some code:
Actions:
export function increment() {
return {
type: 'INCREMENT',
};
}
export function decrement() {
return {
type: 'DECREMENT',
};
}
//different file
export function darkTheme() {
return {
type: 'DARK',
};
}
Reducers:
export default function counterReducer(state = 0, action) {
switch (action.type) {
case 'INCREMENT':
return state + 1;
case 'DECREMENT':
return state - 1;
default:
return 0;
}
}
//different file
export default function themeReducer(state = false, action) {
switch (action.type) {
case 'DARK':
return !state;
default:
return false;
}
}
im calling it like this :
const dispatch = useDispatch();
<button onClick={() => dispatch(increment())}> +</button>
You have to always return state in the default case, in both reducers: every reducer will always be called with every action, so they have to do no modification to the existing state in the default case.
All that said, I want to make you aware that you are learning "vanilla redux" here, which is not the recommended style of redux for production use any more. So while that is great to get an understanding of the underlying concepts, you should not really write code like this in the end. Please follow the official redux tutorials to get an understanding on how to write modern redux. (The fundamentals tutorial will get you started with the style you are using right now and then move into more modern territory, the essentials tutorial will start directly with modern redux - both ways are valid for learning redux)

Redux reducers, object key value

I have hashMap in my redux store, I want change isChecked value for children id: 2. Is it good to make it on state like this (operating on state)?
My hashMap
const childrens = {
1: { name: "Test", isChecked: false },
2: { name: "test2", isChecked: false }
};
Here is my reducer
export const childrensReducer = (state = childrens, action) => {
switch (action.type) {
case "SELECT_CHILDREN":
const id = 2;
state[id].isChecked = !state[id].isChecked;
return { ...state };
}
};
The problem is that you are mutating the state in the reducer with this line:
state[id].isChecked = !state[id].isChecked;
Why immutability is required by redux can be found in official docs:
https://redux.js.org/faq/immutable-data
One way to do is: ( I expect you send id through action.id )
case "SELECT_CHILDREN":
return {
...state,
[action.id]: {
...state[action.id],
isChecked: !state[action.id].isChecked
}
};
These kind of state operations are easier when an array is used for state.
It's not a good practice to mutate the state like you did.
There are different approaches of changing the state. Take a look at the below link to get some more information and examples.
https://www.freecodecamp.org/news/handling-state-in-react-four-immutable-approaches-to-consider-d1f5c00249d5/
Its not a good practise to mutate state, since react depends on immutability for a lot of its features.
Consider for example lifecycle methods or rerender after comparing state/props(PureComponents)
The problem with mutating state is that when these values are passed as props to children and you try to take some decision on them based on whether the state has updated, the previous props and the current props both will hold the same value and hence the comparisons may fail leading to buggy application
The correct way to update state is
case "SELECT_CHILDREN":
const id = 2;
return {
...state,
[id]: {
...state[id],
isChecked: !state[id].isChecked
}
};

Rehydrate redux-persist stored state from code

I would like to rehydrate the whole state of my app from the Javascript code, just like auto-rehydrate works but on-demand.
Can someone show me an example of this ?
I think I need to emit a REHYDRATE action but I can't see how. And I am not sure it will do the same thing as auto-rehydrate.
If you want to programmatically replace your entire app state, it seems you can do what you want with a "plain-old" reducer, no need for plugins:
function todoApp(state = initialState, action) {
switch (action.type) {
case 'APP_STATE_REPLACE':
return action.payload.newState
default:
return state
}
}
and trigger it like this:
store.dispatch({ type: 'APP_STATE_REPLACE',
payload: { newState: { hello: 'world' } }
});

Should actions like showing/hiding loading screens be handled by reducers to related actions or generated by action creators themselves?

Given that you have some global view (showing a loading screen, for example) that you may want to happen in many cases, is it more appropriate to create an action creator/action pair for that behavior or to have the reducer for the related actions handle the transition?
This is hard to describe succinctly, to illustrate what I mean, here's a couple of examples. Which is better, and why?
A
function showLoading () {
return 'SHOW_LOADING';
}
function hideLoading () {
return 'HIDE_LOADING';
}
function fetchPostsRequest () {
return 'FETCH_POSTS_REQUEST';
}
function fetchPostsSuccess () {
return 'FETCH_POSTS_SUCCESS';
}
function doSomethingAsync () {
return dispatch => {
dispatch(showLoading());
dispatch(fetchPostsRequest());
// other logic
dispatch(hideLoading())
dispatch(fetchPostsSuccess());
}
}
function rootReducer (state = {}, action) {
const payload = action.payload;
switch(action) {
case 'SHOW_LOADING':
Object.assign({}, state, {isLoading: true})
break;
case 'HIDE_LOADING':
Object.assign({}, state, {isLoading: false})
break;
// other reducers for handling success/request stuff
}
}
B
function fetchPostsRequest () {
return 'FETCH_POSTS_REQUEST';
}
function fetchPostsSuccess () {
return 'FETCH_POSTS_SUCCESS';
}
function fetchPostsFailure () {
return 'FETCH_POSTS_FAILURE';
}
function doSomethingAsync () {
return dispatch => {
dispatch(fetchPostsRequest());
// good
dispatch(fetchPostsSuccess());
// bad
dispatch(fetchPostsFailure());
}
}
function rootReducer (state = {}, action) {
const payload = action.payload;
switch(action) {
case 'FETCH_POSTS_REQUEST':
Object.assign({}, state, {isLoading: true})
break;
case 'FETCH_POSTS_SUCCESS':
Object.assign({}, state, {isLoading: false /* other logic */})
break;
case 'FETCH_POSTS_FAILURE':
Object.assign({}, state, {isLoading: false /* other logic */})
break;
}
}
I prefer A because it seems more sensible to me to describe these behaviors in one place rather than duplicate the logic of state management, but I have heard a maxim in the redux community that actions should describe what happened or is happening, rather than be imperative commands. In which case, is this just a semantic issue where a term like "ASYNC_OPERATION_START" is better than "SHOW_LOADING"?
Think how this particular piece of code will evolve.
Use this to make decisions.
For example, you are likely to have more than one set of items that can be loading. You may eventually have two lists of items side by side, or one below the other. Thus you will want them to have separate isLoading state just like they have separate lists of IDs.
How would the code change in both options? It seems that having less actions is simpler because this lets you keep isLoading state of the particular list close to other information about it, and also not worry that you forgot to reset its state in the action creator. So in this case I'd choose option B.
On the other hand, if we're talking about a use case like showing a UI notification, I'd probably fire that as a separate action. It exists fairly independently of the server response that caused it: the notification needs to be hidden after a while, two notifications may live on the screen at the same time, etc. So, with this use case, option A seems a better fit.
In general, you should ask yourself:
How will this piece of code likely evolve?
Are these two actions really the same one or are they just related but independent?

Resources