I'm using React with Redux and Material UI to build a webapp. The webapp is made of several pages and components. I know that a snackbar or dialog should be directly connected to what the user is doing. However, I'd like to make the snackbar and dialog independent on the pages and components. A use case therefore is displaying a message like background synchronization of your data failed
and an action retry now
. My idea was to render the snackbar on a page called RootFrame
, which is used to wrap all other pages and to dispatch the text of the snackbar as payload of an action.
My Redux action to show a snackbar:
export function showSnackbar(message: string) {
return {
type: SHOW_SNACKBAR,
payload: message
};
}
Of course it might also be good to specify the message in the action instead of taking the message as argument but that's not my problem right now. The problem is: How can I use this system and display a snackbar with an action? Can I change my action to
export function showSnackbar(message, action) {
return {
type: SHOW_SNACKBAR,
payload: {
message,
action
}
};
}
and render my snackbar in the RootFrame
like
<Snackbar
message={this.props.message}
ref='snackbar'
onDismiss={() => this.props.dispatch(dismissSnackbar())}
action='retry now'
onActionTouchTap={() => this.props.dispatch(this.props.action)}
/>;
When the snackbar is dismissed, an action changes a variable in the state: snackbar.visible = false
. This is used to activate the snackbar (it is rendered when snackbar.visible === true
). When the user clicks on retry now
, the action to start the sync (which is passed to the component as props) should be dispatched. The problem is very similar when using dialogs. So not only the text to display but also the next possible actions have to be passed to the component.
Do you think using Redux like this is ok or is there a better solution?
Actually, right now usign redux was changed a little bit. We use createAction
from redux-act
, properly we use createReducer
further. In a component we use connect decorator or class from react-redux
. Connector provides redux state, dispatched actions, parent props. So for our snackbar we have:
actions:
export const showMessageTop = createAction();
export const closeMessageTop = createAction();
Reducer:
import {createReducer} from 'redux-act';
import * as ac from '../actionCreators/messageTop';
export default createReducer(
{
[ac.showMessageTop]: (state, messageText) => ({messageText}),
[ac.closeMessageTop]: () => ({messageText: ''}),
},
{
messageText: window.location.search === '?login=1'
? 'Welcome'
: '',
}
)
And a component(use decorator instead of class):
import {closeMessageTop} from '../../actionCreators/messageTop';
import MessageTop from './MessageTop';
@connect(state => ({
// gettext: gettext(state.locale.messages),
messageText: state.messageTop.messageText,
}))
export default class MessageTopContainer extends React.Component {
...
<button onClick={...bindActionCreators({onClose: closeMessageTop}, dispatch)}/>
So in current props we have this.props.messageText
. And we can show this bar if we have message, or we can invoke closeAction
which sets up messageText
in empty string.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With