Using ReactJS how to subscribe multiple onSnapshot collection changes in Firestore

Viewed 388

How to use multiples "onSnapshot" changes using Reactjs?

Does someone has used multiples "onSnapshot" in a ReactJs app?

In this video React Firebase CRUD Tutorial Maksim Ivanov show that we can subscribe to firestore Changes by returning teh "onSnapshot" output, like this:

React.useEffect(() => {
return db.collection("dashboars").onSnapshot((snapshot) => {
  snapshot.forEach(doc => {
    dashboardsData.push({ ...doc.data(), id: doc.id });
  });
  setDashboards(dashboardsData);
});
}, []);

In my case, each "dashboards" has "cards" collection with "devicesId". In another collecton there is the relative devicesId with name and status.

I need to show any change in the dashboard, card, and devices on the screen.

Collection "dashboards" /dashboards/OKtApgxGYeMDst/cards/KgKXJrg9SDvXVC returns {devicedId:"esp32_456194"}

Dashboard name: "DASHBOARD 01"
..Card name: "esp32_AF49AC (dev)"
..Card name: "esp32_455FE8"
..Card name: "esp32_45A134"
..Card name: "esp32_456194"
....DeviceId: "esp32_456194"

Collection "devices"

DevideId: "esp32_456194"
--> name: "ED 01", status: "on"
--> name: "ED 02", status: "off"
--> name: "SD 01", status: "off"
--> name: "SD 02", status: "off"

desired mockup

2 Answers

As I mentioned in the comments, you can listen to the devices collection alone if this is the only data that will change. Since you mentioned that you have no way of filtering devices down by Dashboard you can do the following to listen to it and change the data in the dashboard layout (assuming that the dashboardsData array will not be emptied):

db.collection("devices").onSnapshot((snapshot) => {
  snapshot.forEach(doc => {
    // using every() to be able to break the loop without a full iteraction
    dashboardsData.forEach.every(function(element) {
       // not sure this is how you populate but doing it as eg.
       if(element.id == doc.id){
         element.data = doc.data();
         return false 
       }
       else {
         return true
       }
    })
  });
  setDashboards(dashboardsData);
});

Better later than never. I come back here to explain the solution of how to subscribe to multiple snapshot collection changes in Firestore using ReactJS. I am new to using ReactJS. That is why it was not obvious to me.

I divided each snapshot into separate components. ReactJS handles the onChange event normally and updates the page based on each ID. In my case, I observe the change in three related collections, including Dashboard, Cards, Devices, see below:

DashboardInput.js

import { CardsInput } from "./CardsInput";
export const DashboardInput = () => {
  const classes = useStyles();
  const [dashboards, setDashboards] = React.useState([]);
  React.useEffect(() => {
    const db = app.firestore();
    return db.collection("dashboards").where(...).onSnapshot((snapshot) => {
      const dashboardData = []
      snapshot.forEach(doc => {
        dashboardData.push({ ...doc.data(), id: doc.id })
      }
      );
      setDashboards(dashboardData);
    })
  }, []);
  return (
    <ul>
        {dashboards.map(dashboard => (
                <li key={dashboard.id}><CardsInput dashboardId={dashboard.id} /></li>
        ))}
    <ul/>
  )
};

CardsInput.js

import { DevicesInput } from "./DevicesInput";
export const CardsInput = ({ dashboardId }) => {
  const [cards, setCards] = React.useState([]);
  React.useEffect(() => {
    const db = app.firestore();
    return db.collection("dashboards").doc(dashboardId).collection("cards").onSnapshot((snapshot) => {
      const cardData = []
      snapshot.forEach(doc =>
        cardData.push({ ...doc.data(), id: doc.id })
      );
      setCards(cardData);
    })
  }, [dashboardId]);
  return (
    <ul>
      {cards.map(card => (
              <li key={card.id}><DevicesInput devicesId={card.devices} /><li/>
      ))}
    <ul/>
  );
};

DevicesInput

export const DevicesInput = ({ devicesId }) => {
    const [devices, setDevices] = React.useState([]);
    React.useEffect(() => {
        const db = app.firestore();
        return db.collection("devices")
            .where(...).onSnapshot((snapshot) => {
                const deviceData = []
                snapshot.forEach(doc =>
                    deviceData.push({ ...doc.data(), id: doc.id })
                );
                setDevices(deviceData);
            })
    }, []);
    return (
            <ul>
                {devices.map(device => (
                    <li key={device.id}>{device.value}</li>
                ))}
            </ul>
    );
};

And it works very well :-)

Related