Hi, is there a method which can be used from the reducer to display messages.
It seems like we need to be able to provide snacks as a property for this to work. It can be done with getDerivedStateFromProps so that a snacks or queue property gets mapped to the state if it gets updated (by say, redux updating the props with a new snack). It would also require some kind of callback on the snack being closed so we could remove it from the redux state. That may already exist.
I'm not the maintainer, but I have the same requirement. I was just thinking about it when I saw your issue.
Follow up, I just implemented this pretty quickly.
// SnackbarProvider.js
static getDerivedStateFromProps(nextProps, prevState) {
if (nextProps.snacks !== prevState.snacks) {
return { snacks: nextProps.snacks };
}
return null;
}
...
handleDismissOldest = () => {
if (this.props.onSnackClose) {
this.props.onSnackClose(this.state.snacks[0].id);
}
...
}
...
handleCloseSnack = id => {
if (this.props.onSnackClose) {
this.props.onSnackClose(id);
}
...
}
...
SnackbarProvider.propTypes = {
...,
onSnackClose: PropTypes.func,
snacks: PropTypes.arrayOf(PropTypes.any)
}
I can provide a array of snacks an onSnackClose callback (a redux action creator) to the SnackbarProvider. This way I can show the snacks from my store, and also remove them from state when they are closed and/or time out.
It works great. Thoughts on implementation?
This would help alot. I'm using redux with saga, using an old notification package which uses redux. This enables me to add notifications from the saga reducer where API calls resides. I cannot implement this package due to Component context. This does not exist in the saga reducer. Its bad practice to pass context in actions/reducers.
Please add support for this.
Planning to add the support for this, as a lot of users are coming from the redux world.
Contribution / suggestions are welcome.
I have the same issue. For some reason my code is using react-toastify to dispatch notifications into redux store. But I don't know why. Surely it should be a one off event?
My current plan is to remove the redux reducer and make the snack bars fire with enqueSnackbar
Please, anyone, let me know if there is a good reason why it should remain in redux?
Planning to add the support for this, as a lot of users are coming from the redux world.
Contribution / suggestions are welcome.
I think we could simplify my above example and the existing code quite a bit with the Hooks API. I'm just wondering how you feel about going down that road and releasing the feature/update in tandem with the Hooks API stability.
@iamhosseindhv, could you let us know the plans or progress on this one? I'd love to have the redux with notistack and I'm wondering if it is in the nearest future. Thank you!
Hi guys, first of all, thank you @iamhosseindhv for this amazing package!
I'm really new to React and using it only for a side project so I'm aware that my solution isn't perfect but it might help or inspire someone.
Here is my implementation to have a centralized way to display notifications using snackbars, I've created actions and reducers allowing me to add/remove notifications to/from redux store, and then I've created a Notifier component which subscribes to the list of notifications and is responsible to display them using this package. This way any components subscribing to the redux store can display a notification by dispatching the addNotification action. And also because I'm using redux-thunk to perform ajax requests from my actions I have access to dispatch so can also display a notification by dispatching the addNotification action again.
I know that my post isn't useful in term of adding Redux support to this package, but I thought that it might help someone who wants to integrate the existing package with Redux now.
Here is the code:
App into SnackbarProvider// ./app.js
ReactDOM.render(
<Provider store={store}>
<SnackbarProvider>
<App/>
</SnackbarProvider>
</Provider>, document.getElementById('app'));
let notification = {
key: 1 // unique ID across notifications
message: 'My notification'
type: 'info' // used to set the variant for snackbars
}
// ./redux/actions.js
export const addNotification = (notification) => ({
type: 'ADD_NOTIFICATION',
notification: notification
});
export const removeNotification = (key) => ({
type: 'REMOVE_NOTIFICATION',
key: key
});
// ./redux/reducers.js
let defaultState = {
nextNotification: -1, // used for notifications keys
notifications: [] // contains the list of notifications
};
const reducers = (state = defaultState, action) => {
switch (action.type) {
case 'ADD_NOTIFICATION':
let key = state.nextNotification + 1; // increment notification key
return {
...state,
nextNotification: key, // save new notification key in state
notifications: [{...action.notification, key: key}, ...state.notifications] // add notification with incremented key at the start of the list
};
case 'REMOVE_NOTIFICATION':
return {
...state,
notifications: state.notifications.filter(notification => notification.key !== action.key) // remove notification from the list for given key
};
default: return state;
};
export default reducers;
Notifier component to subscribe to the list of notifications and display them using enqueueSnackbar// ./components/Notifier.js
import React from 'react';
import { withSnackbar } from 'notistack';
import { bindActionCreators } from 'redux';
import { connect } from 'react-redux';
import { removeNotification } from './../redux/actions';
class Notifier extends React.Component
{
constructor (props) {
super(props);
/**
* local state used to store the key of the displayed notifications
* to avoid displaying them multiple times
*/
this.state = {
displayed: []
}
}
render = () => {
const { notifications } = this.props;
notifications.map(notification => {
setTimeout(() => {
// If notification already displayed, abort
if (this.state.displayed.filter(key => key === notification.key).length > 0) {
return;
}
// Display notification using Snackbar
this.props.enqueueSnackbar(notification.message, {variant: notification.type});
// Add notification's key to the local state
this.setState({displayed: [...this.state.displayed, notification.key]});
// Dispatch action to remove the notification from the redux store
this.props.removeNotification(notification.key);
}, 300);
});
return null;
}
}
const mapStateToProps = (store) => {
return {
notifications: store.state.notifications
}
};
const mapDispatchToProps = (dispatch) => {
return bindActionCreators({ removeNotification }, dispatch);
};
export default connect(mapStateToProps, mapDispatchToProps)(withSnackbar(Notifier));
Notifier component to App// ./components/App.js
import React from 'react';
import CssBaseline from '@material-ui/core/CssBaseline';
import Header from './Header';
import SearchPage from "./SearchPage";
import Notifier from "./Notifier";
export default class App extends React.Component {
render() {
return (
<React.Fragment>
<CssBaseline/>
<Notifier/> // Will display any notifications dispatched
<Header/>
<SearchPage/>
</React.Fragment>
);
}
}
Thanks @natepage for the great example you provided. 馃憤馃徏鉂わ笍
I cleaned up the code and changed it a little bit, and made a codesandbox here.
I'd like to know what everybody thinks about this. This solution can potentially be an alternative to adding new code to notistack to make it compatible with redux.
@natepage great job! I'd like to contribute a little bit.
Your reducer could define default options which could be overwritten. Something like this:
const defaultOptions = {
variant: 'info',
anchorOrigin: {
vertical: 'bottom',
horizontal: 'right',
autoHideDuration: 1000,
},
}
// ...
case 'ADD_NOTIFICATION': {
const { options, ...rest } = action.notification
return {
...state,
notifications: [
...state.notifications,
{
...rest,
options: { ...defaultOptions, ...options },
},
]
}
}
This way we keep our components DRY:
this.props.addNotification({
key: new Date().getTime() + Math.random(),
message: 'Something went wrong.',
options: {
variant: 'error',
}
})
@taschetto Thank you, I've updated my code! :)
Redux example has been added to the examples folder plus more info in README. Thanks @natepage for the contribution.
hi is there any wat to pass an action to enqueueSnackbar and disaptch the action on exit of snackbar ? like this ?
dispatch(passedAction())
}}
Most helpful comment
Hi guys, first of all, thank you @iamhosseindhv for this amazing package!
I'm really new to React and using it only for a side project so I'm aware that my solution isn't perfect but it might help or inspire someone.
Here is my implementation to have a centralized way to display notifications using snackbars, I've created
actionsandreducersallowing me to add/remove notifications to/from redux store, and then I've created aNotifiercomponent which subscribes to the list of notifications and is responsible to display them using this package. This way any components subscribing to the redux store can display a notification by dispatching theaddNotificationaction. And also because I'm usingredux-thunkto perform ajax requests from my actions I have access todispatchso can also display a notification by dispatching theaddNotificationaction again.I know that my post isn't useful in term of adding Redux support to this package, but I thought that it might help someone who wants to integrate the existing package with Redux now.
Here is the code:
AppintoSnackbarProviderNotifiercomponent to subscribe to the list of notifications and display them usingenqueueSnackbarNotifiercomponent toApp