Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

event bus in React?

I'm mainly using Vue, and just recently picked up React. Loving it so far, and its quite similar in a lot of ways to Vue, which makes learning it way easier.

Now, let's consider two siblings component. I want to trigger something in component number one, when something happens in component number two. In Vue you can just bind window.bus = new Vue, and then emit in one of the components bus.$emit('event') and bind in the mounted() of the second component bus.$on('event', this.doSth).

How can you achieve that in React?

like image 718
Tomasz Rup Avatar asked Nov 16 '18 00:11

Tomasz Rup


2 Answers

Event Bus is only a Global Function Register, can you use it

class _EventBus {

    constructor() {
        this.bus = {};
    }

    $off(id) {
       delete this.bus[id];
    }

    $on(id, callback) {
        this.bus[id] = callback;
    }

    $emit(id, ...params) {
        if(this.bus[id])
            this.bus[id](...params);
    }
}

export const EventBus = new _EventBus();

The export const prevent multiple instances, making the class static

like image 172
Sveen Avatar answered Sep 29 '22 10:09

Sveen


For those that are still searching, look at this article: https://www.pluralsight.com/guides/how-to-communicate-between-independent-components-in-reactjs

The solution uses:

document.addEventListener for $on;

document.dispatchEvent for $emit;

document.removeEventListener for $off;

In my use case I had a component that contained a Refresh button that would trigger a data refresh in other components.

I did everything as it was presented in the article. In case you're using React with Functional Components, you might want to use the following useEffect:

  useEffect(() => {
    // The component might unmount when the request is in progress.
    // Because of this an error will appear when we'll try to 'setData'.
    let isMounted = true

    const getData = () => {
      reqData(db, path)
        .then(result => {
          if (isMounted) {
            setData(result) // This is a useState
          }
        })
    }

    eventBus.on('refreshData', (data) => {
      getData()
    })

    getData()

    return () => {
      isMounted = false
      eventBus.remove('refreshData')
    }

    // Do not change the end of this useEffect. Keep it as it is. It simulates componentDidMount.
    // eslint-disable-next-line
  }, [])
like image 31
Flavius Avatar answered Sep 29 '22 10:09

Flavius