I'm having an issue using Redux Toolkit. I want to push an object to my initial state called selectedData which is an array, this gives me the error "TypeError: undefined is not an object (evaluating 'state.selectedData.push')".
I've been following https://redux-toolkit.js.org/usage/immer-reducers and they literally write their reducer logic the same as mine. I have no idea why it doesn't work for me.
Their code example:
const todosSlice = createSlice({
name: 'todos',
initialState: [],
reducers: {
todoAdded(state, action) {
// "Mutate" the existing state, no return value needed
state.push(action.payload)
},
todoDeleted(state, action.payload) {
// Construct a new result array immutably and return it
return state.filter(todo => todo.id !== action.payload)
}
}
})
My code
import { createAsyncThunk, createSlice } from "@reduxjs/toolkit";
export const exerciseItemSlice = createSlice({
name: "exerciseItem",
initialState: { selectedData: [] },
reducers: {
saveSelectedItemIdsToRedux: (state, action) => {
state.selectedData.push(action.payload);
},
resetSelectedItemIds(state, action) {
return state.itemSelectedData;
}
},
}
);
// Action creators are generated for each case reducer function
export const { saveSelectedItemIdsToRedux, resetSelectedItemIds } = exerciseItemSlice.actions;
export default exerciseItemSlice.reducer;
The only difference is that I'm passing a state called selectedData, I have tried with initialState only as well.
EDIT: Updating with all relevant code as the issue can't be reproduced with above code, indicating the issue should be somewhere else?
rootReducer.js
import counterReducer from "./counterSlice";
import texterReducer from "./testSlice";
import setsTextReducer from "./setsTextSlicer";
import templateReducer from "./templateSlice";
import setsScreenReducer from "./setsScreenSlice";
import exerciseBrowserReducer from "./exerciseBrowserSlice";
import exerciseItemReducer from "./exerciseItemSlice";
import { combineReducers } from "redux";
const rootReducer = combineReducers({
counter: counterReducer,
texter: texterReducer,
setsText: setsTextReducer,
template: templateReducer,
setsScreen: setsScreenReducer,
exercise: exerciseBrowserReducer,
exerciseItem: exerciseItemReducer,
});
export default rootReducer;
store.js
import { configureStore } from "@reduxjs/toolkit";
import {
persistStore,
persistReducer,
FLUSH,
REHYDRATE,
PAUSE,
PERSIST,
PURGE,
REGISTER,
} from 'redux-persist'
import AsyncStorage from "@react-native-async-storage/async-storage";
import rootReducer from "./rootReducer";
const persistConfig = {
key: 'root',
version: 1,
storage: AsyncStorage,
//blacklist: [rootReducer.exerciseItem]
};
const persistedReducer = persistReducer(persistConfig, rootReducer);
const store = configureStore({
reducer: persistedReducer,
// https://github.com/reduxjs/redux-thunk
middleware: getDefaultMiddleware =>
getDefaultMiddleware({
serializableCheck: {
ignoredActions: [FLUSH, REHYDRATE, PAUSE, PERSIST, PURGE, REGISTER],
},
})
});
export const persistor = persistStore(store);
export { store };
UPDATE
I did the good old remove and re-add and now it's working. Renamed the slice/reducer as it had the same name as another component(Feels weird but that might have been the issue?). I've compared my old code to the now working and I can't find any difference, so my best bet would be that the renaming was the issue.
CodePudding user response:
Redux persists serialize (converting to string) your state data in order saved in Async Storage. After serialization, you can't access the array method including Array.push.
Try to parse the array before using the array method.
saveSelectedItemIdsToRedux: (state, action) => {
const serializedData = JSON.parse(state.selectedData)
state.selectedData = serializedData.push(action.payload);
}
Note: JSON.parse sometimes fails when you work with an array with nested objects.
CodePudding user response:
Hope this helps! Remove arrow function and use it like
export const exerciseItemSlice = createSlice({
name: "exerciseItem",
initialState: { selectedData: [] },
reducers: {
// below line is the change
saveSelectedItemIdsToRedux(state, action){
state.selectedData.push(action.payload);
},
resetSelectedItemIds(state, action) {
return state.itemSelectedData;
}
},
}
