Could there have been a better way of coding this? (Beginner) React.js

Viewed 59

This is what I've been taught how to map through arrays with lists. I was wondering if there would be a better way to improve this by keeping it DRY.

I know I could make a single array with objects, however, it's for 3 different columns on a page.

If I were to make changes in the future and maintain the list, would this be sufficient enough?

const groceryList = [
  { Dairy: "Eggs"},
  { Dairy: "Milk"},
  { Dairy: "Cheese"},
];
const shoppingList = [
  { toBuy: "Soap"},
  { toBuy: "Garbage bags"},
];
const getHomeDepot = [
  { getTools: "Plywood"},
  { getTools: "Nails"},
]
{groceryList &&
            groceryList.map((ingredients) => {
              return (
                <ul>
                  <li>
                    {ingredients.Dairy}
                  </li>
                </ul>
              );
{shoppingList &&
            shoppingList.map((items) => {
              return (
                <ul>
                  <li>
                    {items.ToBuy}
                  </li>
                </ul>
              );
{getHomeDepot &&
            getHomeDepot.map((tools) => {
              return (
                <ul>
                  <li>
                    {tools.getTools}
                  </li>
                </ul>
              );
2 Answers

I would make the list into an object, and the different lists into keys. This way, the lists will be easy to add to as they are arrays and you can add list types as keys to the object as needed.

const lists = {
    dairy: ["Eggs", "Milk", "Cheese"],
    buy: ["Soap", "Garbage Bags"],
    tools: ["Plywood", "Nails"]
};

As far as populating the columns... there should only be 1 <ul> surrounding the list items, so this should be outside of the map method. To be dry, you can make a method like this:

const populateListItems = (list) => {
    return list.map((listItem) => (
        <li>{listItem}</li>
    ))
};

and then use it to populate your column list items like so:

<div class="col-1">
{list.dairy.length && (
    <ul>
        {populateListItems(list.dairy)}
    </ul>
)}
</div>
<div class="col-2">
{list.buy.length && (
    <ul>
        {populateListItems(list.buy)}
    </ul>
)}
</div>
<div class="col-3">
{list.tools.length && (
    <ul>
        {populateListItems(list.tools)}
    </ul>
)}
</div>

To make this code even more concise, you can use Object.keys to create as many columns as you need dependent on how many list keys are in the "list" object. This will return the same thing as above.

Object.keys(list).map((key, index) => (
    <div class=`col-${index}`>
        <ul>
            {populateListItems(list[key])}
        </ul>
    </div>
));

I would take a cue from React-Native's FlatList component. At a minimum you want a component that can render an array of items using a renderItem function and can set mapped keys.

const FlatList = ({
  data = [],
  renderItem,
  getKey = (_, i) => i // <-- return array index by default
}) =>
  data.map((el, index) => (
    <React.Fragment key={getKey(el, index)}>
      {renderItem(el, index)}
    </React.Fragment>
  ));

const groceryList = [{ Dairy: "Eggs" }, { Dairy: "Milk" }, { Dairy: "Cheese" }];
const shoppingList = [{ toBuy: "Soap" }, { toBuy: "Garbage bags" }];
const getHomeDepot = [{ getTools: "Plywood" }, { getTools: "Nails" }];
const primitives = ['Bill', 'Ted', 'Socrates'];

const FlatList = ({ data = [], renderItem, getKey = (_, i) => i }) =>
  data.map((el, index) => (
    <React.Fragment key={getKey(el, index)}>
      {renderItem(el, index)}
    </React.Fragment>
  ));

function App() {
  return (
    <div>
      <FlatList
        data={groceryList}
        renderItem={(el) => <div>{el.Dairy}</div>}
      />

      <ul>
        <FlatList
          data={shoppingList}
          renderItem={(el) => <li>{el.toBuy}</li>}
        />
      </ul>

      <ol>
        <FlatList
          data={getHomeDepot}
          getKey={(el, i) => el.getTools}
          renderItem={(el) => <li>{el.getTools}</li>}
        />
      </ol>

      <ul>
        <FlatList
          data={primitives}
          renderItem={(name, i) => <li>{i} : {name}</li>}
        />
      </ul>
    </div>
  );
}

const rootElement = document.getElementById("root");
ReactDOM.render(
  <App />,
  rootElement
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.13.1/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<div id="root"></div>

Related