Search code examples
javascriptreactjsreact-nativepublish-subscribe

using publish subscribe in react makes the component to unmount and mount


I'm trying to implement pubsub (publish-subscribe) in reactjs. Every time an event has listened, then component unmounts and then mounts again. The following are the components:

ComponentA

when the button is clicked, publish an event with payload (i.e item).

import PubSub from 'pubsub-js';
import React from 'react';
import { Button } from 'react-native';

interface ComponentAProps {}

const ComponentA: React.FC<ComponentAProps> = ({}) => {
  return (
    <Button
      title="add items"
      onPress={() => {
           console.log('published')
           PubSub.publish('ADD_ITEMS', { item: { title: 'someItem' } })
        }
      }
    />
  );
};

export default ComponentA;

ComponentB

listens for events, if any, add the payload to items. renders the items.

import React, { useEffect, useState } from 'react';
import { Text, View } from 'react-native';

interface ComponentBProps {}

interface IItem {
  title: string;
}

type IItems = IItem[];

const ComponentB: React.FC<ComponentBProps> = ({}) => {
  const [items, setItems] = useState<IItems>([]);

  useEffect(() => {
    console.log('mounted');
    /**
     * add item to items
     */
    PubSub.subscribe('ADD_ITEMS', (item: IItem) => {
      setItems([...items, item]);
    });
    return () => {
      console.log('unmounted');
      PubSub.unsubscribe('ADD_ITEMS');
    };
  });

  let renderItems = items.map((item) => (
    <View>
      <Text>{item.title}</Text>
    </View>
  ));

  return <View>{renderItems}</View>;
};

export default ComponentB;

the following is the output of the log if the button is clicked 3 times:

  • mounted
  • published
  • unmounted
  • mounted
  • published
  • unmounted
  • mounted
  • published
  • unmounted
  • mounted

Solution

  • Have you tried adding the second argument in useEffect in order to use it like componentDidMount? I'm talking about the empty array []. The way you implement it now is the same as componentDidUpdate and runs on every rerender.

    You can read more here