Redux reducer state is undefined at production - redux

I have react-redux app which works fine without error during development, but in production, It doesn't work.
I've completely removed redux-dev-tolls etc but no chance.
I'm getting this error;
TypeError: Cannot read property 'isLoading' of undefined
I declared signInStatus, and isLoading inside of react render function like this;
const {signin, signInStatus} = this.props
const {
isLoading,
isSucceeded,
idErrorMessage,
passwordErrorMessage,
generalErrorMessage
} = signInStatus;
Connection;
const reduxInjected = connect(({signInStatus}) => ({signInStatus}), {
signin,
signInResetForm,
signinStorage
})(LoginEmailPasswordForm);
....
Reducer;
const signInStatus = (state = {isLoading: false, isSucceeded: false}, action) => {
switch (action.type) {
// Hot Module Replacement
case EPIC_END:
return {isLoading: false, isSucceeded: false};
case ...:
return {...state, isLoading: false, isSucceeded: false};
case ...:
case ...:
case ...:
return {isLoading: true, isSucceeded: false};
case ...:
case ...:
const {accessToken, idToken, expiresIn} = action;
let expiresAt = JSON.stringify((action.expiresIn * 1000) + new Date().getTime());
return {isSucceeded: true, token: {accessToken, idToken, expiresAt}};
case ...:
return {isSucceeded: true, isLoggedIn: true, token: action.token, user: action.user};
case ...:
return {}
case ...:
const newState = {}
const {error} = action;
...
return {...newState, isLoading: false, isSucceeded: false};
case ...:
return {...state, isLoggedIn: true, user: action}
case ...:
return {}
default:
return {...state}
}
}
You can see signInStatus has initial state, but it says it's undefined
What could be the reason?
Thank you.

It was about UglifyJsPlugin
plugins: [
// Don't Minify JS, redux doesn't like it
// new UglifyJsPlugin({
// sourceMap: true,
// compress: false,
// }),
],

Related

converting to redux tool kit and getting "Unhandled Rejection (TypeError): state.push is not a function"

i'm stuck while converting an old project to redux tool kit getting an "Unhandled Rejection (TypeError): state.push is not a function" error. i haven't got to grips with the action/thunk and reducer immutability yet. The alerts are working but then the error msg.
import axios from 'axios';
import { setAlert } from '../alerts/alertSlice';
const slice = createSlice({
name: 'auth',
initialState: {
token: localStorage.getItem('token'),
isAuthenticated: null,
loading: true,
user: null,
},
reducers: {
registerSuccess: (state, action) => {
const { payload } = action.payload;
state.push({
payload,
isAuthenticated: true,
loading: false,
});
},
registerFail: (state, action) => {
localStorage.removeItem('token');
state.push({
token: null,
isAuthenticated: false,
loading: false,
user: null,
});
},
},
});
const { registerSuccess, registerFail } = slice.actions;
export default slice.reducer;
// Register User
export const register =
({ name, email, password }) =>
async (dispatch) => {
const config = {
headers: {
'comtent-Type': 'application/json',
},
};
const body = JSON.stringify({ name, email, password });
try {
const res = await axios.post('/api/users', body, config);
dispatch({
type: registerSuccess,
payload: res.data,
});
} catch (err) {
const errors = err.response.data.errors;
if (errors) {
errors.forEach((error) => dispatch(setAlert(error.msg, 'danger')));
}
dispatch(registerFail());
}
};
.push is an array function to add a new item at the end of an array - your state is not an array.
You probably wanted to do something along the lines of
state.token = null
state.isAuthenticated = false
state.loading = false
state.user = null

get the same state for different requests

i have this action:
export const connectToServer = (url, config, method) => {
return (dispatch) => {
dispatch({type: CONNECTION_START});
axios({
method: method,
url: url,
data: config
})
.then((response) => {
dispatch({type: CONNECTION_LOADING_SUCCESS, payload: response.data});
})
.catch((error) => {
dispatch({type: CONNECTION_LOADING_ERROR, payload: error.response.data});
})
}
};
And 2 identical reducers:
const initialState = {
data: null,
isLoading: false,
error: null
};
export const connectToServerReducer = (state = initialState, action) => {
switch (action.type) {
case CONNECTION_START :
return {...state, isLoading: true};
case CONNECTION_LOADING_SUCCESS :
return {...state, isLoading: false, data: action.payload, error: null};
case CONNECTION_LOADING_ERROR:
return {...state, isLoading: false, data: null, error: action.payload};
default :
return state
}
};
export const differentUrlConnectToServerReducerTest = (state = initialState, action) => {
switch (action.type) {
case CONNECTION_START :
return {...state, isLoading: true};
case CONNECTION_LOADING_SUCCESS :
return {...state, isLoading: false, data: action.payload, error: null};
case CONNECTION_LOADING_ERROR:
return {...state, isLoading: false, data: null, error: action.payload};
default :
return state
}
};
My store looks like this:
const rootReducer = combineReducers({
allUsersData: connectToServerReducer,
testData: differentUrlConnectToServerReducerTest
});
const configureStore = () => createStore(rootReducer, applyMiddleware(thunk));
export default configureStore
Then i use redux hooks to get a state with data in my components
const allUsersData = useSelector(state => state.allUsersData);
const testData = useSelector(state => state.testData);
const dispatch = useDispatch();
Finally i dispatch them
dispatch(connectToServer(`${BASE_URL}user/allUsersWithPets`, null, 'get'));
dispatch(connectToServer(`${BASE_URL}fakeUrl`, null, 'get'));
I receive a correct data in allUsersData, but also i receive it in testData but i should receive in testData an initial state(empty object), because url is a fake
Where am i wrong?
You need to separate the reducers, use different initial states for example:
connectToServer.js
connectToServerTest.js
Or you can try to add the test object to the initial state of connectToServerReducer.(not a good solution though)
const initialState = {
data: null,
testData: null,
isLoading: false,
error: null
};
Remember that arrays affections won't assign values but addresses, so the "data" array is the same array in both the connectToServerReducer and connectToServerReducerTest.
Second problem, you are calling the same action name in both reducers, this causes them not only to share the same variable from the previous problem I told you, but they share the same value assigned to them as well.
Just change them to:
CONNECTION_TEST_LOADING_SUCCESS
CONNECTION_TEST_LOADING_ERROR
CONNECTION_TEST_START
PS:
instead of using:
export const connectToServer = (url, config, method) => {
return (dispatch) => {
...
}
}
Use:
export const connectToServer = (url, config, method) => (dispatch) => {
...
}

Hot to fix ngrx auto overrite all another stores when dispach any

I need help whit Angular ngRx store. I spend couple days for this, but I can't figure out((
I have 2 store in my app and when i dispatch one of them (store.dispatch(new LoadProperties() )) my previous value from another store overrated
this my effects, requcers and app.module
recipes.effects.ts
#Effect() loadRecipes$ = this.dataPersistence.fetch(fromRecipes.LOAD_RECIPES, {
run: (action: LoadRecipes, state: RecipesState) => {
return this.recipesService.getRecipes()
.pipe(map((res: Recipe[]) => new LoadRecipesSuccess(res)));
},
onError: (action: LoadRecipes, error) => {
this.toaster.errorSnackBar(error.statusText, 'Cant fetch categories');
return of(new LoadRecipesError(error));
}
});
properties.effects.ts
#Effect() loadProperties$ = this.dataPersistence.fetch(fromProperties.LOAD_PROPERTIES, {
run: (action: LoadProperties, state: PropertiesState) => {
return this.propertiesService.getProperties()
.pipe(map((res: Property[]) => new LoadPropertiesSuccess(res)));
},
onError: (action: LoadProperties, error) => {
this.toaster.errorSnackBar(error.statusText, 'Cant fetch properties');
return of(new LoadPropertiesError(error));
}
});
export interface AppState { recipes: fromRecipes.RecipesState; properties: fromProperties.PropertiesState;
}
imports: [
SharedModule,
BrowserModule.withServerTransition({appId: 'my-app'}),
HttpClientModule,
ToastrModule.forRoot(),
BrowserAnimationsModule,
StoreModule.forRoot(fromApp.appReducer),
EffectsModule.forRoot(fromApp.appEffects),
StoreDevtoolsModule.instrument({ maxAge: 10 }),
NxModule.forRoot()
...]
upd
this is recipe reducer
Hey there! recipes reducers
witch (action.type) {
case RecipesActions.LOAD_RECIPES:
return {
...state, // the incoming state
loading: true // turn loading indicator on
};
case RecipesActions.LOAD_RECIPES_SUCCESS:
return {
...state, // the incoming state
recipes: action.payload,
loaded: true, // recipes were loaded
loading: false, // turn loading indicator off
};
case RecipesActions.LOAD_RECIPES_ERROR:
return {
...state, // the incoming state
loaded: false, // the recipes were loaded
loading: false, // turn loading indicator off
};
this is properties.reducer
switch (action.type) {
case PropertiesActions.LOAD_PROPERTIES:
return {
...state, // the incoming state
loading: true // turn loading indicator on
};
case PropertiesActions.LOAD_PROPERTIES_SUCCESS:
return {
...state, // the incoming state
properties: action.payload,
loaded: true, // properties were loaded
loading: false, // turn loading indicator off
};
case PropertiesActions.LOAD_PROPERTIES_ERROR:
return {
...state, // the incoming state
loaded: false, // the properties were loaded
loading: false, // turn loading indicator off
};
Seems like the reducers don't have a default case, which it should have otherwise the state will be undefined.
switch (action.type) {
... other cases ...
default:
return state;
}

Redux store reset when navigating (after I've refactored reducer)

I am trying the refactor my reducer into two "sub" reducers and combine them before exporting to store.js. However, when I am navigating in my app the state of my notificationReducer gets reseted, and not the other reducers. I am unsure of what might be the problem and I've followed the guide (sort of) from redux.js.org =>
Separating Data Handling by Domain
Any thoughts or tips on how you've refactored reducers?
notificationReducer.js
import {
FETCHING_NOTIFICATION_STATUS, // NOTIFICATION
FETCHING_NOTIFICATION_STATUS_SUCCESS,
FETCHING_NOTIFICATION_STATUS_FAILURE,
FETCHING_NOTIFICATION_DATA, // NOTIFICATION
FETCHING_NOTIFICATION_DATA_SUCCESS,
FETCHING_NOTIFICATION_DATA_FAILURE,
FETCHING_MARK_NOTIFICATION_AS_UNSEEN, // NOTIFICATION
FETCHING_MARK_NOTIFICATION_AS_UNSEEN_SUCCESS,
FETCHING_MARK_NOTIFICATION_AS_UNSEEN_FAILURE
} from '../Actions/actionTypes'
const fetchingData = {
isFetching: false,
dataFetched: false,
error: false,
errorMsg: '',
}
const initialState = {
notificationStatus: {
...fetchingData,
hasNotifications: false,
},
notificationData: {
...fetchingData,
data: [],
},
markNotification: {
...fetchingData,
isUnseen: false,
},
}
const { notificationStatus, notificationData, markNotification } = initialState
const notificationStatusReducer = (state = notificationStatus, action) => {
switch(action.type) {
case FETCHING_NOTIFICATION_STATUS:
return {
...state,
isFetching: true,
}
case FETCHING_NOTIFICATION_STATUS_SUCCESS:
return {
...state,
isFetching: false,
dataFetched: true,
hasNotifications: action.data,
}
case FETCHING_NOTIFICATION_STATUS_FAILURE:
return {
...state,
isFetching: false,
error: true,
errorMsg: action.errorMsg,
}
default:
return state
}
}
const notificationDataReducer = (state = notificationData, action) => {
switch(action.type) {
case FETCHING_NOTIFICATION_DATA:
return {
...state,
isFetching: true
}
case FETCHING_NOTIFICATION_DATA_SUCCESS:
return {
...state,
isFetching: false,
dataFetched: true,
data: action.data,
}
case FETCHING_NOTIFICATION_DATA_FAILURE:
return {
...state,
isFetching: false,
error: true,
errorMsg: action.errorMsg,
}
default:
return state
}
}
const markNotificationReducer = (state = markNotification, action) => {
switch(action.type) {
case FETCHING_MARK_NOTIFICATION_AS_UNSEEN:
return {
...state,
isFetching: true
}
case FETCHING_MARK_NOTIFICATION_AS_UNSEEN_SUCCESS:
return {
...state,
isFetching: false,
dataFetched: true,
isUnseen: true,
}
case FETCHING_MARK_NOTIFICATION_AS_UNSEEN_FAILURE:
return {
...state,
isFetching: false,
error: true,
errorMsg: action.errorMsg,
}
default:
return state
}
}
const notificationReducer = (state = initialState, action) => {
return {
notificationStatusReducer : notificationStatusReducer(state.notificationStatus, action),
notificationDataReducer : notificationDataReducer(state.notificationStatus, action),
markNotificationReducer : markNotificationReducer(state.markNotification, action),
}
}
export default notificationReducer
You should use combineReducers for such things. So your notificationReducer should be the combination of yours three reducers.
const notificationReducer = combineReducers({
notificationStatusReducer,
notificationDataReducer,
markNotificationReducer
})
Hope it will help

how to convert ES5 to ES6 in redux's reducer

How to convert the below code to ES6: (especially the part after newState.guests = []
case ActionTypes.GetInviteFulfilled: {
const { host, agenda, guests } = action.invite;
const newState = Object.assign({}, state, {
inProgress: false,
success: 'Got invite.',
host,
agenda
});
newState.guests = [];
if (guests) {
newState.guests = Object.keys(guests).map(k => guests[k]);
}
return newState;
}
This might work for you:
case ActionTypes.GetInviteFulfilled: {
const { host, agenda, guests } = action.invite;
return {
...state,
inProgress: false,
success: 'Got invite.',
host,
agenda,
guests: guests ? Object.keys(guests).map(k => guests[k]) : [],
};
}

Resources