I try to build a generic confirm component with redux and native promise. I read Dan Abramovs solution here: How can I display a modal dialog in Redux that performs asynchronous actions? but i am looking for a more generic appoach. Basically i want to do this:
confirm({
type: 'warning',
title: 'Are you sure?',
description: 'Would you like to do this action?',
confirmLabel: 'Yes',
abortLabel: 'Abort'
})
.then(() => {
// do something after promise is resolved
})
The confirm method basically opens the modal and returns a promise. Inside the promise i subscribe my redux store, listen for state changes and resolve or reject the promise:
export const confirm = function(settings) {
// first dispatch openConfirmModal with given props
store.dispatch(
openConfirmModal({
...settings
})
);
// return a promise that subscribes to redux store
// see: http://redux.js.org/docs/api/Store.html#subscribe
// on stateChanges check for resolved/rejected
// if resolved or rejected:
// - dispatch closeConfirmModal
// - resolve or reject the promise
// - unsubscribe to store
return new Promise((resolve, reject) => {
function handleStateChange() {
let newState = store.getState();
if (newState.confirmModal.resolved) {
store.dispatch(closeConfirmModal());
resolve();
unsubscribe();
}
if (newState.confirmModal.rejected) {
store.dispatch(closeConfirmModal());
reject();
unsubscribe();
}
}
let unsubscribe = store.subscribe(handleStateChange);
})
}
My confirm component is connected to redux store and is included once in some kind of layout component - so it is useable on all routes in the app:
class ConfirmModal extends Component {
constructor(props) {
super(props)
}
confirm() {
this.props.dispatch(resolveConfirmModal());
}
abort() {
this.props.dispatch(rejectConfirmModal());
}
render() {
// my modal window
}
}
export default connect(
state => ({
confirmModal: state.confirmModal
})
)(ConfirmModal);
Reducer/Action looks like this:
export const openConfirmModal = (settings) => {
return {
type: 'OPEN_CONFIRM_MODAL',
settings
};
};
export const resolveConfirmModal = () => {
return {
type: 'RESOLVE_CONFIRM_MODAL'
};
};
export const rejectConfirmModal = () => {
return {
type: 'REJECT_CONFIRM_MODAL'
};
};
export const closeConfirmModal = () => {
return {
type: 'CLOSE_CONFIRM_MODAL'
};
};
const initialState = {
open: false,
type: 'info',
title: 'Are you sure?',
description: 'Are you sure you want to do this action?',
confirmLabel: 'Yes',
abortLabel: 'Abort',
};
export const ConfirmModalReducer = (state = initialState, action) => {
switch (action.type) {
case 'OPEN_CONFIRM_MODAL':
return { ...action.settings, open: true };
case 'RESOLVE_CONFIRM_MODAL':
return { ...state, resolved: true };
case 'REJECT_CONFIRM_MODAL':
return { ...state, rejected: true };
case 'CLOSE_CONFIRM_MODAL':
return initialState;
default:
return state;
}
};
The redux part is working. My confirm window can be open/closed and renders depending on my options. But how i can define a promise in my confirm method that can be resolved in my component? How i get everything connected?
Found a working Solution!
Found a solution that is pretty much what i was looking for:
- The modal properties are driven by my Redux state
- The modal component is included once AND it lives inside my applicition not as a different rendered app like here:http://blog.arkency.com/2015/04/beautiful-confirm-window-with-react/
- The confirm method returns a native promise that is resolved/rejected driven by Redux state
What do you think?