Flash Messages


Updated May 2nd, 2023

Another Look at Flash Messaging

Developing a application leveraging MUI I debated the use of their snack bar components or the react-hot-toast library (500k weekly), (The MUI docs also mentioned the “notistack” library for stacking toasts 545k weekly).

But I also wanted to see if the global state using useImmerReducer in combo with a simple “FlashMessages” component dropped in your main layout was still easy and valid.

The main area flash messaging is needed is around login and registration. Pretty frustrating to try and register and get no feedback and no action due to something like that username is taken or other validation error. Client side can get disabled to although inputs may have there own message the flash message need to come from the server.

Global state still the right answer. I believe so in case the user goes to another page.

React Hot Toast is just too easy to implement

Original Post

Ultimately the goal of flash messages is to show an error message that either disappears automatically or you can click to close or a combination of both.

You want to have an array of messages as strings And then the loop through these to show them on the UI.

You want them to be positioned in a way so they are visible even if your form is way down the screen you don’t want them to be fixed at the top. You also want to avoid any layout shifting as the messages are added or removed so absolute positioning may be good here.

You also wanted to be flexible on that if Sending a request sent back an array of errors as strings, each of these should be added.

I usually store these in global state managed to be a reducer function and updated with dispatch actions.

Dispatching an action with a string is pretty easy You just push on to the end of the array. But again it needs to be flexible enough to also be able to handle an array of strings and so push doesn’t work.

So in the flash message case I changed draft.flashMessages.push(action.value) to draft.flashMessages = […action.value] but to keep any existing draft.flashMessage = […draft.flashMessages, …action.value]

But this doesn’t work because it breaks the ability to send a typical string by spreading in each character of a string as its own message.

So I can get it to work as a string or I can get it to work as an array of strings But I can’t get it to handle simultaneously.

The fix was to put two conditional checks in the flash message case in the switch statement.

The first conditional check is if type of action. Value equals a string then draft. / Messages. Push action. Value

The second conditional check is if array that is array action dot value then draft out flash messages equals the existing draft messages and then spread action value

That seems to work and this also seems like a better solution than looping through an array of errors and dispatching an action for each item in the array. In other words, I think it’s better to send one dispatch action with a payload than it is to dispatch multiple actions.

The handling of the UI

I’m going to refer to Max’s Next JS course here because in his “global context” section (section 10) he shows how to do this. Nice implementation with the timing out of the message and the ability for the user to click to remove immediately. Pending messages also do not time out or have a click-to-remove button.

Placement of the Message on a Form

Where should form success messages go? A few options:

Relative to viewport

Under the submit button

Over-top of the form blocking the form from being submitted again.

I you are blocking the form should you shrink the form area?

Should you allow the form to come back up without a page refresh?