HiveBrain v1.2.0
Get Started
← Back to all entries
snippetjavascriptTip

Mapping data structures to React components

Submitted by: @import:30-seconds-of-code··
0
Viewed 0 times
componentsdatastructuresmappingreact

Problem

Have you ever wanted to quickly transform an array into a table or an object into a tree view? One of the benefits of React is that you can easily map data structures to components, even customizing them to your needs.
The simplest mapping is an array of primitives to a list of elements. All you really need is Array.prototype.map() to render each item as a <li> element. In addition to that, you should use a key prop to help React identify each item. Finally, wrap the result in an <ol> or <ul> element, depending on whether you want an ordered or unordered list.
A very similar use-case is mapping an array of primitives to a table. The process is almost identical, but this time you render each item as a <tr> element with two <td> children. The first <td> contains the index of the item, while the second one contains the item itself.
For more complex structures, such as arrays of objects, you'll need a more sophisticated component. Instead of rendering each item as a <tr> element, you'll need to render each object as a <tr> element with a <td> for each key in the object. This way, you can create a table with rows dynamically created from an array of objects and a list of property names.
To get the keys and iterate over them, you'll combine Object.keys(), Array.prototype.filter(), Array.prototype.includes(), and Array.prototype.reduce(). This will produce a filteredData array, containing all objects with the keys specified in propertyNames.

Solution

const DataList = ({ isOrdered = false, data }) => {
  const list = data.map((val, i) => <li key={`${i}_${val}`}>{val}</li>);
  return isOrdered ? <ol>{list}</ol> : <ul>{list}</ul>;
};

const names = ['John', 'Paul', 'Mary'];

ReactDOM.createRoot(document.getElementById('root')).render(
  <>
    <DataList data={names} />
    <DataList data={names} isOrdered />
  </>
);


A very similar use-case is mapping an array of primitives to a table. The process is almost identical, but this time you render each item as a <tr> element with two <td> children. The first <td> contains the index of the item, while the second one contains the item itself.
For more complex structures, such as arrays of objects, you'll need a more sophisticated component. Instead of rendering each item as a <tr> element, you'll need to render each object as a <tr> element with a <td> for each key in the object. This way, you can create a table with rows dynamically created from an array of objects and a list of property names.
To get the keys and iterate over them, you'll combine Object.keys(), Array.prototype.filter(), Array.prototype.includes(), and Array.prototype.reduce(). This will produce a filteredData array, containing all objects with the keys specified in propertyNames.
> [!CAUTION]
>
> This component does not work with nested objects and will break if there are nested objects inside any of the properties specified in propertyNames.

Code Snippets

const DataList = ({ isOrdered = false, data }) => {
  const list = data.map((val, i) => <li key={`${i}_${val}`}>{val}</li>);
  return isOrdered ? <ol>{list}</ol> : <ul>{list}</ul>;
};

const names = ['John', 'Paul', 'Mary'];

ReactDOM.createRoot(document.getElementById('root')).render(
  <>
    <DataList data={names} />
    <DataList data={names} isOrdered />
  </>
);
const DataTable = ({ data }) => {
  return (
    <table>
      <thead>
        <tr>
          <th>ID</th>
          <th>Value</th>
        </tr>
      </thead>
      <tbody>
        {data.map((val, i) => (
          <tr key={`${i}_${val}`}>
            <td>{i}</td>
            <td>{val}</td>
          </tr>
        ))}
      </tbody>
    </table>
  );
};

const people = ['John', 'Jesse'];

ReactDOM.createRoot(document.getElementById('root')).render(
  <DataTable data={people} />
);
const MappedTable = ({ data, propertyNames }) => {
  let filteredData = data.map(v =>
    Object.keys(v)
      .filter(k => propertyNames.includes(k))
      .reduce((acc, key) => ((acc[key] = v[key]), acc), {})
  );
  return (
    <table>
      <thead>
        <tr>
          {propertyNames.map(val => (
            <th key={`h_${val}`}>{val}</th>
          ))}
        </tr>
      </thead>
      <tbody>
        {filteredData.map((val, i) => (
          <tr key={`i_${i}`}>
            {propertyNames.map(p => (
              <td key={`i_${i}_${p}`}>{val[p]}</td>
            ))}
          </tr>
        ))}
      </tbody>
    </table>
  );
};

const people = [
  { name: 'John', surname: 'Smith', age: 42 },
  { name: 'Adam', surname: 'Smith', gender: 'male' }
];
const propertyNames = ['name', 'surname', 'age'];

ReactDOM.createRoot(document.getElementById('root')).render(
  <MappedTable data={people} propertyNames={propertyNames} />
);

Context

From 30-seconds-of-code: data-mapping-components

Revisions (0)

No revisions yet.