Publisher subscriber pattern in React.js

#react #javascript

 

Last week I learnt a pattern called Publisher subscriber(Pub-Sub) pattern and tried to implement it in react. This can easily be done with React's context API or any third party library like Redux, but I took a different approach.

tl;dr: NOTE: This code is not production ready. Complete working app can be found here

 

What is Pub/Sub pattern?

According to Wikipedia

Pub-Sub is a messaging pattern where senders of messages, called publishers, do not program the messages to be sent directly to specific receivers, called subscribers, but instead categorize published messages into classes without knowledge of which subscribers, if any, there may be. Similarly, subscribers express interest in one or more classes and only receive messages that are of interest, without knowledge of which publishers, if any, there are.

In simple words, the publisher and subscriber are unaware of each other. All the communication between them is taken through events which are emitted from the publisher and notifies subscriber. As shown bellow


Pubsub pattern source msd blog

Implementing this in React

I have tried to use the Pub-Sub pattern to react in the most simplified manner that I could do with only two events (on and emit).

In this example, I'll be creating a simple modal which will act as a subscriber. Let's get started:

 

Modal.js

export const Modal = () => {
  const [content, setContent] = useState("no content");
  const [showModal, setShowModal] = useState(false);

  const setMessage = (message) => {
    setContent(message);
    setShowModal(true);
  };
  const clearMessage = () => {
    setContent("");
    setShowModal(false);
  };

  if (showModal) {
    return (
      <div>
        <h2>{content}</h2>
        <button onClick={clearMessage}>Close Modal </button>
      </div>
    );
  }
  return null;
};

 

Then I need an event bus which will be solely responsible for passing messages around. Here it is:

 

eventBus.js

const event = {
  list: new Map(),
  on(eventType, eventAction) {
    this.list.has(eventType) || this.list.set(eventType, []);
    if (this.list.get(eventType)) this.list.get(eventType).push(eventAction);
    return this;
  },

  emit(eventType, ...args) {
    this.list.get(eventType) &&
      this.list.get(eventType).forEach((cb) => {
        cb(...args);
      });
  }
};

 

Here I have on event actions on and emit for a more complex system you can other event systems you can add other events such as clear, off etc.

Once we have our event system on its place let hook this event system in our modal

 

Modal.js

export const Modal = () => {
  const [content, setContent] = useState("no content");
  const [showModal, setShowModal] = useState(false);

  const setMessage = (message) => {
    setContent(message);
    setShowModal(true);
  };
  const clearMessage = () => {
    setContent("");
    setShowModal(false);
  };

  useEffect(() => {
    event.on("showModal", setMessage).on("clearAllMessage", clearMessage);
  }, []);
  if (showModal) {
    return (
      <Container>
        <h2>{content}</h2>
        <button onClick={clearMessage}>Close Modal </button>
      </Container>
    );
  }
  return null;

 

Next in order to complete the puzzle we need final pice that is Publisher which will emit the events

 

ModalPublisher.js

export const ModalPublisher = {
  message: (content) => {
    event.emit("showModal", content);
  },
  clearAllMessage: () => {
    event.emit("clearAllMessage");
  }
};

Okay once everything is on the place you can now we can use it in App.js

 

App.js

function App() {
  return (
    <div className="App">
      <Modal showModal={true} />
      <h1
        onClick={() => {
          ModalPublisher.message("this is the content from App");
        }}
      >
        Hello CodeSandbox
      </h1>
      <h2>Start editing to see some magic happen!</h2>
    </div>
  );
}

Conclusion

This code is still not production-ready still there are many edge case to cover. I have used this pattern for Modal and toast.

 

Source

https://dev.to/avinash8847/publisher-subscriber-pattern-in-react-js-42h8

 

보론

저와 같이 publisher-subscriber 패턴을 처음 접한 분이라면, 위의 코드를 봐도 또잉?? 할 겁니다. 그래서 위의 코드를 디버깅한 내용을 정리해봤습니다.

 

먼저 위의 코드가 돌아가는 순서입니다.

 

1. Modal.js의  useEffect에서 event.on에 함수를 등록하고 있습니다. 이 부분이 가장 먼저 실행 됩니다. 이 코드의 결과  event객체의 on에 setMessage함수와 clearMesssage함수가 등록되게 됩니다. 정확히 말하면 map에 list[]를 set해놓고 그안에 함수를 담아 놓습니다.

2. App.js에서 this is the content from App을 클릭하게 되면, ModalPublisher.js의 message 이벤트가 움직이게 됩니다. 이 message이벤트는 event버스에 신호를 주는 역할(publisher)을 하게 되죠.

3. 그럼 그 신호와 eventType에 따라, 1에서 등록해 놓았던 해당하는 이벤트를 실행합니다.

4. 위의 예에서는 클릭을 하면,  event객체의 on에 등록된 setMessage함수가 실행되게 되구요.

5. setMessage함수는  Modal.js내의 state를 변경하면서 컴포넌트를 re-rendering 시킵니다.

 

이처럼 eventBus에 함수를 등록해(subscribe) 놓으면, 경우에 따라서 publisher가 eventBus를 Emit하게 됩니다. eventBus를 매개로하서 Pulisher와 subscriber과 독립적으로 움직이게 되는 구조입니다.

 

+ Recent posts