DEV Community

Cover image for EventManager - an agnostic alternative to Redux
Chad Steele
Chad Steele

Posted on • Edited on

EventManager - an agnostic alternative to Redux

Redux is a VERY powerful tool, if you need it. I have yet to need it. Javascript comes with powerful event management out of the box. Why not use it? I don't like unnecessary complexity or code and hate centralized bloat, dogma, boilerplate or scaffolding in general and so, I wrote the following library... I hope you like it and can use it.

In short, this code enables you to quickly share state or any info between arbitrary components anywhere in the React hierarchy without having to worry about context, props, etc. It also has some fun features like get(event) and echo(event) that enables a newly rendered component to get an old event that fired before it was rendered.

EventManager - a simple javascript class

You can use EventManager with or without React and I recommend making it a singleton global instance (optional, but optimal)

/**
 * EventManager - simplifies events 
 */
export class EventManager {
  constructor(node) {
    this.node = node || this.node || window;
    this.cache = {};  // old events
  }

  //returns the last time this event was dispatched - even prior to your "listener"
  get(event) {
    return this.cache[event];
  }

  //dispatches the last instance of this event
  echo(event) {
    this.dispatch(this.get(event));
  }

  //listen for and respond to events
  addListener(event, handler, useCapture) {
    if (!event) return;

    handler =
      handler ||
      function (e) {
        if (!e) return null;
        return e.details || null;
      };

    this.node.addEventListener(event, handler, useCapture);
  }

  // stop listening
  removeListener(event, handler) {
    if (!event) return;
    this.node.removeEventListener(event, handler);
  }

  //dispatch an event with forgiving syntax
  dispatch(event, params, quiet) {
    if (!event) return;
    if (!event.type) {
      let e = event;
      let n = e.event || e.name || e;
      let p = e.params || e.data || params;
      if (typeof p === 'object') {
        p = Object.assign({}, e.params, e.data, params);
      }
      event = new CustomEvent(n, { detail: p });
    }

    this.node.dispatchEvent(event);
    this.cache[event.type] = event;
    try {
      if (!quiet) log(`dispatch ${event.type}(${event.detail ? JSON.stringify(event.detail) : ''})`);
    } catch (ex) { }
  }
}

React Components

EventHandler

e.g. <EventHandler event="myEventName" handler={onMyEvent}/>

export function EventHandler(props) {

  let complete = (props.event && props.handler);
  if (!complete) {
    throw (new SyntaxError('<EventHandler> is missing required properties.  <EventHandler event="event-name"  handler={func}  />'));
  }

  //manage events
  useEffect(() => {
    //componentDidMount, componentDidChange
    if (complete) events.addListener(props.event, props.handler, props.useCapture);
    return () => {
      //componentWillUnmount
      events.removeListener(props.event, props.handler);
    };
  });

  return props.children || null;
}

For example, a simple event handler might look like...

    const onMyEvent = e => {
        setDetails(e.detail);
    }

Dispatch

e.g. <Dispatch event="myEventName" expr={a < b} wait={1000} />
If (expr) dispatch an event when something is (re)rendered and/or after a wait period.

export function Dispatch(props) {
  var expr = props.if || props.expr;
  expr = expr == null ? true : expr;
  var wait = props.wait || props.delay || 0;
  useEffect(() => {
    if (expr && props.event) {
      setTimeout(function () {
        events.dispatch(props.event, props.params);
      }, wait);
    }
  });
  return props.children || null;
}

In closing, I do plan to add these to git, npm, etc. someday, but for now I'd appreciate your feedback and especially if you find this useful. Please don't bother defending or evangelizing Redux or strict typing. They're both great and that's not the point of this post. I'm a weird C++'r who actually likes javascript "duck typing" and hope to use it powerfully.

Sincerely,
Chad Steele

Top comments (0)