'What is the ideal way to use subscription with react apollo GraphQL

I am working on a react project which uses GraphQl for API integration, which I did perfectly. Now I am working on a module where I need to use subscription.

What I am doing

  1. I have charts to show one UI, which I have created successfully using ReCharts.
  2. So initially I a getting data from query and displaying it on UI which works totally fine.
  3. Than as per requirement There is some live data which I am getting through subscription i.e web socket
  4. So what I am doing is I stored query data in a state and when I got the live data I am appending the live data to that state and UI is updating correctly.

Issue I am facing

  1. As I have many charts on UI so I am conditionally checking for which chart I am getting data and than appending to the particular one.

  2. But what happens is when I got a lot of data which is coming every 2-6 seconds it hangs the browser after sometime, like after 10 minutes or 15 minutes, which is bit frustrating.

  3. I don't know What is wrong in this, may be my approach is not good or something else

My code what I did

    // below query is for getting list of factoories
  //const { loading: loadingFactoryy, data: factoryList } = useQuery(   FACTORYLIST);
  // from above query I ll get data like below state
  // as I am not connected to backend so I am taking data statically
  const [factoryList, setFactoryList] = useState([
    {
      factoryId: 16,
      factoryName: "factory one",
      __typename: "user_factoryNames"
    },
    {
      factoryId: 17,
      factoryName: "factory two",
      __typename: "user_factoryNames"
    },
    {
      factoryId: 18,
      factoryName: "factory Three",
      __typename: "user_factoryNames"
    },
    {
      factoryId: 19,
      factoryName: "factory four",
      __typename: "user_factoryNames"
    }
  ]);

My Machine code

    // below query to get the machines for each factories, if i click on
  //factoryone it will give me all machines of factory one
  // const [
  //    getMachines,
  //    { loading: loadingMachines, data: machineData },
  // ] = useLazyQuery(FACTORYMACHINEBYID);
  //I am using lazyquery so when I click I ll get the data

  // useEffect(() => {  this will run when page loades first time
  //    if (factoryList !== undefined) {
  //        if (factoryList.getUserFactorydNames.length > 0) {
  //            getInitialDataFun({
  //                variables: {
  //                    factoryId:
  //                        factoryList?.getUserFactorydNames[parseInt(activeDashboard)]
  //                            ?.factoryId,
  //                },
  //            });
  //        }
  //    }
  // }, [active_tab, factoryId, getInitialDataFun]);

  //all functions for factories click

  let active_tab = localStorage.getItem("active_tab") || 0;
  const [active_menu, setActive_menu] = useState(Number(active_tab));
  const [machineList, setmachineList] = useState([
    {
      chartId: 12,
      chartBame: "machine1",
      data: [
        {
          dValue: 5,
          dName: "Data1"
        },
        {
          dValue: 10,
          dName: "Data2"
        }
      ]
    },
    {
      chartId: 13,
      chartBame: "machine2",
      data: [
        {
          dValue: 5,
          dName: "Data1"
        },
        {
          dValue: 10,
          dName: "Data2"
        }
      ]
    }
  ]);

My subscription code

    // my subscription code
  // const {
  //    data: LiveDataMachine,
  //    error: errorLiveDataMachine,
  // } = useSubscription(LIVEDATAMACHINEFUN, {
  //    variables: { topic: { topic: 'livemessage/' } },
  // });
  const factoryClick = (li, ind) => {
    setActive_menu(ind);
    localStorage.setItem("active_tab", ind);
  };

  //My live data looks like below

  // {
  //   "chartId": 16,
  //   "chartBame": "machine1",
  //   "data": [
  //     {
  //       "dValue": 7,
  //       "dName": "Data1"
  //     },
  //     {
  //       "dValue": 18,
  //       "dName": "Data2"
  //     }
  //   ]
  // }

  // So what I am doing is whenever I am getting the live data
  //I am looping it with main machine data and checking for chartId
  //once it matches I am appending the data like below



    // useEffect(() => {
  // if(machineList){
  //   machineData.map((li,ind)=>{
  //     if(LiveDataMachine.chartId===li.chartId){
  //       setmachineList(machineList=>[...machineList,LiveDataMachine])
  //     }
  //   })
  // }
  // }, [LiveDataMachine]);

   // but what is hapenning is it is updating the UI so fast that my browser is getting hanged

  return (
    <div className="App">
      <FactoryComp
        factoryData={factoryList}
        active_menu={active_menu}
        factoryClick={factoryClick}
      />
      <hr />
      <MachinesComp machineData={machineList} />
    </div>

above is how I am writing my code and managing GraphQl subscription, I don't know what I am doing wrong which is making my browser hangs alot here I am looking for a correct approach by which I can use subscription with my query.

Here is my working code I have written everything as a comment for better uderstanding



Solution 1:[1]

Looks like you are calling setmachineList in the if inside a render. It will endlessly cause component updates, thereby cycling it. Perhaps it is better to move this logic to useEffect?

useEffect(() => {
  if(machineList){
    machineData.forEach((li,ind)=>{
      if(LiveDataMachine.chartId===li.chartId){
        setmachineList(machineList=>[...machineList,LiveDataMachine])
      }
    })
  }
}, [LiveDataMachine]);

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Валера Битковский