i have a code to update the count value of object. now i need to convert it to immutable.js. i am pretty much new to immutable.js. so how can i convert this code to immutable.js format.
import * as actionTypes from '../actions/actionTypes';
const initialState={
ingredients: {
salad:0,
meat:0,
cheese:0,
},
totalprice:40
}
const ingredientCost = {
cheese:20,
meat:30,
salad:10,
};
const reducer = (state = initialState, action) => {
switch (action.type) {
case actionTypes.ADD_INGREDIENT:
return {
...state,
ingredients:{
...state.ingredients,
[action.ingredientName] : state.ingredients[action.ingredientName]+1
},
totalprice: state.totalprice + ingredientCost[action.ingredientName],
};
case actionTypes.REMOVE_INGREDIENT:
return {
...state,
ingredients:{
...state.ingredients,
[action.ingredientName] : state.ingredients[action.ingredientName]-1,
},
totalprice: state.totalprice - ingredientCost[action.ingredientName],
};
default:
return state;
}
};
export default reducer;
i tried to change the code to immutable format:
import * as actionTypes from '../actions/actionTypes';
import Immutable from 'immutable';
const initialState=Immutable.fromJS({
ingredients: {
salad:0,
meat:0,
cheese:0,
},
totalprice:40
})
const ingredientCost = {
cheese:20,
meat:30,
salad:10,
};
const reducer = (state = initialState, action) => {
switch (action.type) {
case actionTypes.ADD_INGREDIENT:
return state.ingredients[action.ingredientName].merge(state.ingredients[action.ingredientName]+1)
case actionTypes.REMOVE_INGREDIENT:
return {
...state,
ingredients:{
...state.ingredients,
[action.ingredientName] : state.ingredients[action.ingredientName]-1,
},
totalprice: state.totalprice - ingredientCost[action.ingredientName],
};
default:
return state;
}
};
export default reducer;
but while doing this i am not able to update the state. i am getting initialstate but i dont know how to update it.
thanks in advance
since initialState is immutable object, You cant use state.ingredients, You should use
state.set() / state.setIn() or
state.update() / state.updateIn() or
state.merge() / state.mergeIn()
read: https://facebook.github.io/immutable-js/docs/#/Map
Related
I have used created two actions and their respective reducers. When i dispatch any single action, both actions initial states are being saved to state where the parameters of the states are duplicated.
actions/index.js
import { COUNTER_CHANGE, UPDATE_NAVIGATION } from "../constants";
export function changeCount(count) {
return {
type: COUNTER_CHANGE,
payload: count,
};
}
export function updateNavigation(obj) {
return {
type: UPDATE_NAVIGATION,
payload: obj,
};
}
reducers.js
import { COUNTER_CHANGE, UPDATE_NAVIGATION } from "../constants";
import logger from "redux-logger";
const initialState = {
count: 0,
navigation: {},
};
export const countReducer = (state = initialState, action) => {
switch (action.type) {
case COUNTER_CHANGE:
return {
...state,
count: action.payload,
};
default:
return state;
}
};
export const updateNavigation = (state = initialState, action) => {
switch (action.type) {
case UPDATE_NAVIGATION:
return {
...state,
navigation: action.payload,
};
default:
return state;
}
};
// export default countReducer;
reducer/index.js
import { countReducer, updateNavigation } from "../reducers/countReducer";
import { combineReducers } from "redux";
const allReducers = combineReducers({
countReducer,
updateNavigation,
});
export default allReducers;
Dispatching actions
componentDidMount = () => {
const { navigation } = this.props;
this.props.updateNavigation(navigation);
};
const mapDispatchToProps = (dispatch) => {
return { ...bindActionCreators({ changeCount, updateNavigation }, dispatch) };
};
As we can see here I have triggered only updateNavigation action. But it updates states with duplicate parameters in redux state as shown below
The expected o/p will be
countReducer : {count : 0}
updateNavigation : {navigation :{}}
The shape of state for each reducer is incorrect. See defining-state-shape docs and try this:
export const countReducer = (state = { count: 0 }, action) => {
switch (action.type) {
case COUNTER_CHANGE:
return {
...state,
count: action.payload,
};
default:
return state;
}
};
export const updateNavigation = (state = { navigation: {} }, action) => {
switch (action.type) {
case UPDATE_NAVIGATION:
return {
...state,
navigation: action.payload,
};
default:
return state;
}
};
import { countReducer, updateNavigation } from "../reducers/countReducer";
import { combineReducers } from "redux";
const allReducers = combineReducers({
countReducer,
updateNavigation,
});
const store = createStore(allReducers);
console.log(store.getState());
Output:
{ countReducer: { count: 0 }, updateNavigation: { navigation: {} } }
In your action/index.js
import { COUNTER_CHANGE, UPDATE_NAVIGATION } from "../constants";
export function changeCount(count) {
dispatch( {
type: COUNTER_CHANGE,
payload: count,
});
}
export function updateNavigation(obj) {
dispatch({
type: UPDATE_NAVIGATION,
payload: obj,
});
}
Dispatch the data without returning it
How would i convert this with usage of Immutable JS.
fromJS to wrap initial state and setIn method for nested cases.
const initialState = {
allMovies: []
};
const movieReducer = (state = initialState, action) => {
const {type, payload} = action;
switch (type) {
// some actions...
case movieActionTypes.FETCH_MOVIES_SUCCESS: {
return {
...state,
allMovies: {
...state.allMovies,
[payload.movie.id]: {
...state.allMovies[payload.movie.id],
...payload.movie,
ready: false,
},
},
};
}
default:
return state;
}
};
I am working on a proof of concept in react-native and I am using redux-persist. According to what I read the states are automatically assigned in version 5, however I have not managed to rehydrate the state without the case REHYDRATE.
My reducer:
import {ADD_USER} from '../constants/actionTypes';
import { REHYDRATE } from 'redux-persist';
const initialState = {
userName: null,
fetching: false
};
const userReducer = (state = initialState, action) => {
let copied = Object.assign({}, state);
switch (action.type){
case ADD_USER:
copied.userName = action.payload;
break;
case REHYDRATE:
//console.log('Payload desde el reducer ', action.payload);fsdffdsdsfsdfsdf
copied = action.payload.userReducer;
break;
default:
break;
}
return copied;
};
export default userReducer;
My configureStore
const persistConfig = {
key: 'root',
storage,
stateReconciler: autoMergeLevel2,
};
function logger({ getState }) {
return (next) => (action) => {
let returnValue = next(action)
return returnValue
}
}
const persistedReducer = persistCombineReducers(persistConfig, {userReducer});
export default () => {
let store = createStore(persistedReducer, undefined, applyMiddleware(logger));
let persistor = persistStore(store, null, () => {
Alert.alert(
'Current state',
JSON.stringify(store.getState()),
[
{text: 'OK', onPress: () => console.log('OK Pressed')},
],
{ cancelable: false }
);
});
return { store, persistor }
}
My problem was that I returned the state at the end of the method instead of returning it in each case of the switch and this surely broke the auto rehydration. Changing the reducer returns my problem disappeared.
The reducer code was like this:
const initialState = {
userName: null,
fetching: false
};
const userReducer = (state = initialState, action) => {
switch (action.type){
case ADD_USER:{
let copied = Object.assign({}, state);
copied.userName = action.payload;
return copied;
}
default:
return state;
}
};
export default userReducer;
I need to concat an array from my reducer after add to cart button is pressed.
I tried pushed, but it doesn't seem to work.
import { combineReducers } from 'redux';
import { DATA_AVAILABLE,
ADD_TO_CART,
GET_CART_DATA
} from "../actions/" //Import the actions types constant we defined in our actions
let dataState = { data: [], loading:true };
let cartState = { data: [] };
const dataReducer = (state = dataState, action) => {
switch (action.type) {
case DATA_AVAILABLE:
state = Object.assign({}, state, { data: action.data, loading:false });
return state;
default:
return state;
}
};
const cartReducer = (state = cartState, action) => {
switch (action.type) {
case ADD_TO_CART:
state = Object.assign({}, state, { data: [action.data]});
//console.log("state data => "+state.data);
return state;
default:
return state;
}
};
// Combine all the reducers
const rootReducer = combineReducers({
dataReducer,
cartReducer,
// ,[ANOTHER REDUCER], [ANOTHER REDUCER] ....
})
export default rootReducer;
During ADD_TO_CART event, the reducer is replacing all the data each time my add to cart button is clicked. Instead, I need to concat those items so I can show them into my cart list.
Seems like you probably want:
case ADD_TO_CART:
return Object.assign({}, state, {
data : state.data.concat(action.data)
});
If you have the Object Spread syntax available in your app setup (which is turned on by default if you're using Create-React-App), you can simplify that a bit to:
case ADD_TO_CART:
return {...state, data : state.data.concat(action.data) }
I'm trying to map my state to a given component with redux. I have two reducers and are therefore using combineReducers before passing my rootReducer to my store.
const rootReducer = combineReducers({
ctr:counter,
res:result
});
const store = createStore(
rootReducer,
window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__()
);
ReactDOM.render(<Provider store={store}><App/></Provider>, document.getElementById('root'));
registerServiceWorker();
But when I try mapping my state to a given component's props, the state is undefined
const mapStateToProps = state => {
return {
ctr: state.ctr.counter,
storedResults: state.res.results //storedResults is undefined when I try to access it.
}
};
My two reducers look as follows:
counter.js
import * as actionTypes from "../actions";
const initialState = {
counter:0
};
const reducer = (state = initialState, action) => {
switch (action.type) {
case actionTypes.INCREMENT:
return {
...state,
counter: state.counter + 1
};
case actionTypes.DECREMENT:
return {
...state,
counter: state.counter - 1
};
case actionTypes.ADD:
return {
...state,
counter: state.counter + action.val
};
case actionTypes.SUBTRACT5:
return {
...state,
counter: state.counter - 5
};
}
return state;
};
export default reducer;
result.js
import * as actionTypes from "../actions";
const initialState = {
result:[]
};
const reducer = (state = initialState, action) => {
switch (action.type) {
case actionTypes.STORE_RESULT:
return {
...state,
results:state.results.concat({id: new Date(), value:state.counter})
};
case actionTypes.DELETE_RESULT:
// const id = 2;
// const newArray = [...state.results];
// newArray.splice(id,1);
const updatedArray = state.results.filter(result => result.id !== action.resultId);
return {
...state,
results:updatedArray
}
}
return state;
};
export default reducer;
Any idea what the problem might be?
Your initialState in result reducer is result. Just correct it to results.