1

I'm trying to build a React web app (v 16.13.0). I want a flash message component, to display status after a form is submitted. If there is already something standard, that would be preferable, but since I can't find anything, I'm trying to roll my own using this -- https://medium.com/@jaouad_45834/building-a-flash-message-component-with-react-js-6288da386d53 . Here's the component

import React, { useEffect, useState } from 'react';
import Bus from '../Utils/Bus';

import './index.css';

export const Flash = () => {
    let [visibility, setVisibility] = useState(false);
    let [message, setMessage] = useState('');
    let [type, setType] = useState('');

    useEffect(() => {
        Bus.addListener('flash', ({message, type}) => {
            setVisibility(true);
            setMessage(message);
            setType(type);
            setTimeout(() => {
                setVisibility(false);
            }, 4000);
        });


    }, []);

    useEffect(() => {
        if(document.querySelector('.close') !== null) {
            document.
            querySelector('.close').
            addEventListener('click', () => setVisibility(false));
        }
    })

    return (
        visibility && <div className={`alert alert-${type}`}>
                <span className="close"><strong>X</strong></span>
                <p>{message}</p>
            </div>
    )
}

Problem is, web site uses custom code, but doesn't show source for

        Bus.addListener('flash', ({message, type}) => {
            setVisibility(true);
            setMessage(message);
            setType(type);
            setTimeout(() => {
                setVisibility(false);
            }, 4000);
        });

so my question is, how do I add an event listener to a React component?

Edit: In response to the answer given, I created this file ...

localhost:client davea$ cat src/Utils/Bus.js 
import EventEmitter from 'events';
export default new EventEmitter();

but re-compiling my module results in this error ...

./src/components/Flash/index.js
Module not found: Can't resolve '../Utils/Bus' in '/Users/davea/Documents/workspace/chicommons/maps/client/src/components/Flash'

These are the first lines of the file above. Note the second "import" where I'm importing "Bus" ...

import React, { useEffect, useState } from 'react';
import Bus from '../Utils/Bus';

import './index.css';

export const Flash = () => {
Dave
  • 15,639
  • 133
  • 442
  • 830
  • [Handling events](https://reactjs.org/docs/handling-events.html) and [react-toastify](https://www.npmjs.com/package/react-toastify) is just one of many message/alert packages. What is `Bus`? Can you include that code? Also, in react you typically attach event listeners to components and not directly to DOM elements (*this is a react anti-pattern*). – Drew Reese Mar 28 '20 at 18:51
  • Hi @DrewReese. I don't know what Bus is -- that joker on Medium didn't include his code. I want to build a simple component to flash a success message (or better just use an existing one) but this is all I could find and I assume Bus is some kind of event framework I need to apply to my component but I'm not entirely sure. – Dave Mar 29 '20 at 19:57
  • Source for Bus.js is [here](https://medium.com/@jaouad_45834/building-a-flash-message-component-with-react-js-6288da386d53#e43f). – HMR Mar 31 '20 at 07:41
  • Regarding your question "how do I add an event listener to a React component?": You should read more about state and component props in React, as React uses a very different paradigm than the one you're approaching this problem from. Here, it would be more idiomatic to create "Flash" as a child component, and have its parent pass it an "isOpen" prop that will be true/false based on actions taken by the user. See [Thinking in React](https://reactjs.org/docs/thinking-in-react.html) and [Refs and the DOM](https://reactjs.org/docs/refs-and-the-dom.html) – the holla Apr 03 '20 at 01:07
  • This seems like an absurd way to achieve something so simple, if all you want to do is flash a message on a button click, you can achieve this by passing a prop down like https://stackoverflow.com/users/5128949/the-holla said. https://codesandbox.io/s/interesting-nightingale-1vsej. Also I heavily suggest you do some reading up on how react works as you should not be querying for DOM elements within the scope of an actual react component. (https://reactjs.org/docs/faq-internals.html) – Batzz Apr 06 '20 at 18:12

3 Answers3

0

The website included the code: https://medium.com/@jaouad_45834/building-a-flash-message-component-with-react-js-6288da386d53

To set that up, we need to create a new folder in our root directory and name it Utils and create on it a Bus.js file with will contains the following code:
import EventEmitter from 'events';
export default new EventEmitter();

This is all Bus.js is, a simple event emitter.

You can also use react-toastify or useToasts for this.

tudor.gergely
  • 4,800
  • 1
  • 16
  • 22
0

In order to show the flash message, you need to do something like the following.

Bus.emit('flash', {type: 'danger', message: 'error occurred'}); 

I have used the code you have provided and mixed it with a dummy form. Upon submitting the form, the flash message appears successfully.

enter image description here

Live example & working code is here:

https://codesandbox.io/s/dazzling-lamarr-k3cn5

Some notes:

  • I have refactored and removed 2nd useEffect as it is inefficient and unnecessary. The onClick can very well be applied to the close-span-element
  • If you are using redux, you can use create global Flash/Alert message and connect it to the store. Any redux-connected-component can simply work its own logic and dispatch an alert action and render different types of messages.
  • Using ready made libraries are also cool.
gdh
  • 13,114
  • 2
  • 16
  • 28
0

I think what you want is widely known as a Toaster, and you can use a library like React Toastify [https://github.com/fkhadra/react-toastify] with a simple configuration and high customization

Pablo Marcano
  • 2,635
  • 1
  • 11
  • 6