Как стать автором
Обновить

JSX: как разделять логику и отрисовку в разметке, сгенерированной методом map

Уровень сложностиПростой
Время на прочтение3 мин
Количество просмотров7.7K

Давайте представим себе частый кейс - вы с бека получаете какой-то массив данных, из которых вы будете делать разметку, что будет содержимым вашей страницы.

Для примера возьмем список пользователей, и вам надо отрендерить этот список. Вам пришел массив и вы, не теряя времени, прогоняете его через map, создавая, таким образом свою разметку - вот так:

return (
  <ul className="list">
    {users.map(user => (
      <Fragment key={user.name.name}>
        <li>{user.name.name} {user.name.patronomic} {user.name.surname}</li>
        <li>{user.regestrationDate}</li>
        <li>{user.status.description}</li>
      </Fragment>
    ))}
  </ul>
);

Окей, тут все просто. Но давайте представим, что с бека (как это часто бывает) данные вам приходят не чистыми, но их еще надо обрабатывать. Например, отчества может не быть, то есть нужно сделать проверку, а имена и фамилии нужно привести к ловеркейсу.

Также при наличии даты регистрации, привести ее к нужному виду, а если нет, то сгенерить дату и отправить ее на бек.

Ну и напоследок, если статус нужно залить соответствующим стилем из заготовленного словаря, который завязан на отдельном свойстве value; если стиля в словаре нет - сделать какой-нибудь дефолтный.

Делать все эти операции в разметке плохая идея, ведь нам хочется как раз разгрузить разметку, так что давайте сразу все вынесем в отдельные переменные.

Давайте представим как это могло бы выглядеть:

return (
  <ul className="list">
    {users.map(user => {
      const fullName = `
        {user.name.name} 
        {user.name.patronomic ? user.name.patronomic : ''} 
        {user.name.surname}
      `.toLowerCase();
      const date = user.regestrationDate 
        ? moment(user.regestrationDate)
        : null;
      const statusColor = ['В сети', 'Не в сети'].includes(
        user.status.description,
      )
      ? STATUS_COLORS[user.status.value]
      : 'neutral';

      retrun (
        <Fragment key={user.name.name}>
          <li>{fullName}</li>
          <li>{date}</li>
          <li className={statusColor}>{user.status.description}</li>
        </Fragment>
      );
    })}
  </ul>
);

Супер - всего 27 строк кода. А теперь представьте что у вас на проекте все это происходит в компоненте, где разметка занимает несколько сот строк кода (хотя бы). И такие простые утилитарные обработки отвлекают внимание и мешают увидеть общую картину разметки, а это в больших сложных проектах критично.

Что тут можно сделать? Я предлагаю выносить все утилитарные вычисления в отдельную функцию с префиксом "with" или "proxy", которая будет как некая "прослойка" содержать код расчета переменных и передавать их обратно в колбек, который занимается разметкой.

Продемонстрируем. Создадим функцию "withProxyUser", в которую обернем колбек разметки, перенесем в нее все переменные и передадим их обратно в колбек разметки с оригинальным обьектом user. Вот так:

const withProxyUser = callback => user => {
  const fullName = `
    {user.name.name} 
    {user.name.patronomic ? user.name.patronomic : ''} 
    {user.name.surname}
  `.toLowerCase();
  
  const date = user.regestrationDate 
    ? moment(user.regestrationDate)
    : null;
  
  const statusColor = ['В сети', 'Не в сети'].includes(
    user.status.description,
  )
  ? STATUS_COLORS[user.status.value]
  : 'neutral';

  return callback({user, fullName, date, statusColor});
}

return (
  <ul className="list">
    {users.map(
      withProxyUser(({user, fullName, date, statusColor}) => (
        <Fragment key={user.name.name}>
          <li>{fullName}</li>
          <li>{date}</li>
          <li className={statusColor}>{user.status.description}</li>
        </Fragment>
      ))
    )}
  </ul>
);

Обратите внимание как объявляется функция withProxyUser - это множественный колбек. Чтобы не запутаться - первая переменная - это то что мы передаем в withProxyUser - то есть сам колбек; вторая переменная - то что мы получаем вне withProxyUser - то есть переменные из map.

И того наша разметка заметно "похудела", а про withProxyUser можно забыть - даже можно вынести ее в файл с утилитами, что еще больше разгрузит наш компонент.

Вот и все. Держите свою разметку в форме - пожалейте глаза и время коллег.

Спасибо.

Теги:
Хабы:
Всего голосов 4: ↑4 и ↓0+4
Комментарии26

Публикации

Истории

Работа

Ближайшие события

27 августа – 7 октября
Премия digital-кейсов «Проксима»
МоскваОнлайн
28 – 29 сентября
Конференция E-CODE
МоскваОнлайн
28 сентября – 5 октября
О! Хакатон
Онлайн
30 сентября – 1 октября
Конференция фронтенд-разработчиков FrontendConf 2024
МоскваОнлайн
3 – 18 октября
Kokoc Hackathon 2024
Онлайн
7 – 8 ноября
Конференция byteoilgas_conf 2024
МоскваОнлайн