I have an eventEmitter that fires isOnline true or false for when server communications drop. I added 1 if statement to prevent the dispatch firing if the onLine state matches the request to go onLine or offLine. Removing this if fixes the code, but I am stuck with dispatch calls for no reason.
Keep in not this has no issues going from onLine to offLine. It just has issues going from offLine back to onLine.
const setIsOnline = (isOnline: boolean) => {
if (state.isOnline !== isOnline) {
console.log('Online status changed from', state.isOnline, 'to', isOnline);
dispatch({
type: navigatorActions.SET_IS_ONLINE,
payload: isOnline
});
}
};
Here is the reducer for reference. Note the reducer works fine when called. The issue is that if statement prevents it from being called when going online from offline. Taking out the if statement fixes it all, but now I have redundant rerenders.
import {
navigatorActions,
NavigatorState
} from '@shared/utils/domains/context/types';
export const navigatorReducer = (state: NavigatorState, action: any) => {
let updatedState = state;
switch (action.type) {
case navigatorActions.SET_BACK_PATH:
updatedState = { ...state, backPath: action.payload };
break;
case navigatorActions.SET_LOGO_CLICKED:
updatedState = { ...state, logoClicked: action.payload };
break;
case navigatorActions.SET_IS_ONLINE:
console.log('reducer changing', state.isOnline, 'to', action.payload);
updatedState = { ...state, isOnline: action.payload };
break;
default:
return state;
}
return updatedState;
};
With the incomplete code example my guess here is that you've a stale Javascript closure over state.isOnline
in the setIsOnline
handler.
Instead of trying to work around JS closures I suggest just handling the "is online" comparison in the reducer function. Dispatching an action isn't what triggers a React component rerender. The SET_IS_ONLINE
reducer case is unconditionally creating a new state object and this is what is very likely triggering "unnecessary" component state updates.
Update the reducer logic to compare the current state.isOnline
value to the incoming action.payload
value and only update the state if the value will actually change.
Example:
const setIsOnline = (isOnline: boolean) => {
dispatch({
type: navigatorActions.SET_IS_ONLINE,
payload: isOnline
});
};
export const navigatorReducer = (state: NavigatorState, action: any) => {
let updatedState = state;
switch (action.type) {
case navigatorActions.SET_BACK_PATH:
return { ...state, backPath: action.payload };
case navigatorActions.SET_LOGO_CLICKED:
return { ...state, logoClicked: action.payload };
case navigatorActions.SET_IS_ONLINE:
// isOnline will change, return new state
if (state.isOnline !== action.payload) {
return { ...state, isOnline: action.payload };
}
// no isOnline change, return current state
return state;
default:
return state;
}
};