Merge into an object from two different API calls I'm working on an app to compare SDKS (their churn and acquisiton rates). I have created an API with two separate endpoints.
The first, compares one sdk to ther other and spits out that data for each sdk.
The second, simply gets general information about a single sdk.
I'm merging these objects into one, so that all information regarding a single SDK can be found.
Problems I previously had, and might still come up (hopefully fixed by now): When setting the object at the end with setAllSdksInfo(objCopy) there was a problem in which it would not set it ok.
I'm also getting an ESLint warning which states &quot;Function declared in a loop contains unsafe references to variable(s) 'objCopy', 'objCopy', 'objCopy', 'objCopy', 'objCopy', 'objCopy', 'objCopy'&quot; but that doesn't seem to be causing any problems.
import React, { useEffect } from &quot;react&quot;;
import MatrixSquare from &quot;./MatrixSquare&quot;;

function Matrix({ selectedSdks, allSdksInfo, setAllSdksInfo, showMatrix, setShowMatrix }) {

  useEffect(() =&gt; {
    (async () =&gt; {
      const selectedSdksKeys = Object.keys(selectedSdks);
      if (!selectedSdksKeys.length) return;

      setShowMatrix(false);

      let comparedCount = 0;

      const notComparedKeys = [];

      selectedSdksKeys.forEach((key, i) =&gt; {
        for (let j = i + 1; j &lt; selectedSdksKeys.length; j++) {
          if ( allSdksInfo?.[key]?.[&quot;churned_to&quot;]?.hasOwnProperty( selectedSdksKeys[j])) {
            comparedCount += 1;
            if (comparedCount === 3) {
              setShowMatrix(true);
            }
          } else {
            notComparedKeys.push([key, selectedSdksKeys[j]]);
          }
        }
      });

      let objCopy = Object.assign({}, allSdksInfo);

      for (let i = 0; i &lt; notComparedKeys.length; i++) {
        await fetch( `/api/sdk/churn?sdk1_id=${notComparedKeys[i][0]}&amp;sdk2_id=${notComparedKeys[i][1]}`)
          .then((res) =&gt; res.json())
          .then((res) =&gt; {
            const copyPreviousObj = Object.assign({}, objCopy);
            objCopy = { ...objCopy, ...res };
            const resKeys = Object.keys(res);

            resKeys.forEach((key) =&gt; {
              const new_churned_to = objCopy[key][&quot;churned_to&quot;];
              const new_acquired_from = objCopy[key][&quot;acquired_from&quot;];

              if (copyPreviousObj[key]) {
                objCopy[key][&quot;churned_to&quot;] = {
                  ...new_churned_to,
                  ...copyPreviousObj[key][&quot;churned_to&quot;],
                };
                objCopy[key][&quot;acquired_from&quot;] = {
                  ...new_acquired_from,
                  ...copyPreviousObj[key][&quot;acquired_from&quot;],
                };
              }
            });
          });
      }

      selectedSdksKeys.forEach(async (id, i) =&gt; {
        if (allSdksInfo[id]?.[&quot;num_installed_apps&quot;]) return;
        const res = await fetch(`/api/sdk/general_info?sdk_id=${id}`);
        const data = await res.json();
        objCopy[id][&quot;num_installed_apps&quot;] = data[&quot;num_installed_apps&quot;];
        objCopy[id][&quot;acquired_total&quot;] = data[&quot;acquired_total&quot;];
        objCopy[id][&quot;churned_total&quot;] = data[&quot;churned_total&quot;];
      });

      setAllSdksInfo(objCopy);
      setShowMatrix(true);
    })();
  }, [selectedSdks]);
I beleive the issue with

When setting the object at the end with setAllSdksInfo(objCopy) there
was a problem in which it would not set it ok.

Is because Object.assign is not doing what you're expecting it to do, it does not create a deep copy of the source object
TLDR;
When you modify a nested property of the copied object, it will affect the original one, one way of creating a deep copy of the object is JSON.parse(JSON.stringify(obj)) :


const obj_original = {
  a: {
    b: {
      c: 'hello'
    }
  }
}

const obj_copy = Object.assign({}, obj_original);

const deep_copy = JSON.parse(JSON.stringify(obj_original));

obj_original.a.b.c = 'test';

console.log(obj_original); // { a: { b: { c: 'test' } } } 
console.log(obj_copy); // { a: { b: { c: 'test' } } }
console.log(deep_copy); // { a: { b: { c: 'hello' } } }



Keep it DRY :
instead of objCopy[id][&quot;churned_total&quot;] = data[&quot;churned_total&quot;]; you could use destructuring assignment to avoid repeating :
selectedSdksKeys.forEach(async (id, i) =&gt; {
  if (allSdksInfo[id]?.num_installed_apps) return;

  const res = await fetch(`/api/sdk/general_info?sdk_id=${id}`);

  const { num_installed_apps, acquired_total, churned_total } = await res.json();;

  objCopy[id] = {
    ...objCopy[id],
    num_installed_apps, 
    acquired_total, 
    churned_total
  }
});