Best way to join 2 API data sources into 1 react table?

1.8k views Asked by At

I need data from 2 different APIs, both support pagination.

How can I display the joined data in a table in a performant way?

I need to join on their id, but one API returns less data than the other, so I cannot simply match 1 by 1. I need to implement a filter.

Is the only way to brute force map data source A to B?

1

There are 1 answers

0
Matt On BEST ANSWER

If the data comes from two different APIs and you are making to separate requests you have a number of options. My personal preference is to have state in your controller in which you map each response by id and then you can select the additional data by id:

import React, { useState, useEffect } from 'react';
import { keyBy } from 'lodash';

function TableComponent(props) {
  // Destructure your props...I'm assuming you pass some id into fetch data
  const { id } = props;
  
  // State
  const [tableData, setTableData] = useState([]);

  // Load data when id changes
  useEffect(() => {
    fetchData()
  }, [id]);

  async function fetchData() {
    // Get your data from each source
    const apiData_A = await fetchDataFromAPI_A(id);
    const apiData_B = await fetchDataFromAPI_B(id);
    // Key each data set by result ids
    const resultsMappedById_A = keyBy(apiData_A, 'id');
    const resultsMappedById_B = keyBy(apiData_B, 'id');
    // Combine data into a single set
    // this assumes your getting same results from each api
    const combinedDataSet = Object.keys(resultsMappedById_A)
      .reduce((acc, key) => {
        // Destructure results together, merging objects
        acc.push({
          ...resultsMappedById_A[key],
          ...resultsMappedById_B[key]
        });
        return acc;
      }, []);
    setTableData(combinedDataSet);
  }

  async function fetchDataFromAPI_A(id) {
    // Fetch your data and return results
  }

  async function fetchDataFromAPI_A(id) {
    // Fetch your data and return results
  }

  function renderTableRow(data) {
    return (
      <tr>
        <td>{data.id}</td>
        <td>{data.apiAProp}</td>
        <td>{data.apiBProp}</td>
      </tr>
    );
  }


  return (
   <table>
     { tableDataSet.map(renderTableRow) }
   </table>
  );
}

Note, there are probably more efficient ways to do this depending on how you're fetching data and what the responses hold, but the concept provided here should do the trick assuming my assumptions are correct based on the information you have provided.