I am toggling visibility of a modal in react based on result of some logic performed in saga middleware by dispatching action from saga.
I went through:
- Action is being dispatched twice on github
takeEvery/takeLatest is executed twice even though action dispatched only once
- Wasn't very helpful.
Store
export default function configureStore(preloadedState) {
const sagaMiddleware = createSagaMiddleware();
const middlewares = [..otherMiddleware, sagaMiddleware, ...someMoreMiddlewares];
const store = createStore({
// other configuration,
// middleWares
})
sagaMiddleware.run(rootRunner);
return store;
}
Reducer:
const initialState = {
activeSwitch: '1',
modalVisibility: false,
}
export default function reducer(state = initialState, action) {
switch (action.type) {
case 'TOGGLE_MODAL':
return state.set('modalVisibility', !state.get('modalVisibility'));
case 'UPDATE_ACTIVE_SWITCH':
// update active switch
default:
return state;
}
}
Action:
export const switchOption = payload => ({
type: 'SWITCH_OPTION',
payload,
})
export const toggleModal = () => ({
type: 'TOGGLE_MODAL',
})
export const updateActiveSwitch = payload => ({
type: 'UPDATE_ACTIVE_SWITCH',
payload,
})
Component:
import switchOption from 'action';
function Component(props) {
return <div onClick={props.switchOpt(somePayloadParameter)} />;
}
const mapDispatchToProps = state => ({
switchOpt: (somePayloadParameter) => dispatch(switchOption(somePayloadParameter)),
})
export default connect(null, mapDispatchToProps)(Component);
RootSaga:
export default function* rootRunner() {
yield all([ fork(watcher) ])
}
Saga:
function* worker(payload) {
console.log('hey');
yield put({'TOGGLE_MODAL'})
// Perform some task and wait for modal ok button click
yield take('MODAL_OK');
if (taskSuccess) {
yield put({ type: 'UPDATE_ACTIVE_SWITCH', someValue});
yield put({ type: 'TOGGLE_MODAL'}};
}
export default function* watcher() {
while(true) {
yield actionObj = yield take('SWITCH_OPTION');
yield call(worker, actionObj.payload);
}
}
Modal is never visible as 'TOGGLE_MODAL' is being dispatched twice from saga, as a result of watcher
calling worker
twice.
If I put a debugger
just after while(true) {
in watcher
, on page load, that breakpoint is hit twice.
Even if I remove every line from worker
, it is still running twice.
Why is my saga code running twice?
EDIT
Component:
import switchOption from 'action';
function Component(props) {
return <div onClick={props.switchOpt(somePayloadParameter)} />;
}
const mapDispatchToProps = state => ({
// switchOption is action from action.js
switchOpt: (somePayloadParameter) => dispatch(switchOption(somePayloadParameter)),
})
export default connect(null, mapDispatchToProps)(Component);
Redux monitor middleware logs to the console in dev tools following three actions, after executing saga function when it is called onClick
for the first time:
- 'SWITCH_OPTION'
- 'TOGGLE_MODAL' --> with
modalVisibility
set totrue
- 'TOGGLE_MODAL' --> with
modalVisibility
set tofalse
Now the click on div
becomes useless as MODAL never popped up and there is no OK button to click on.