JSX: как «подсушить» разметку, сгенерированную методом map

e9313154e3908444c3fbadd870557bc2.png

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

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

return (
  
    {users.map(user => (
  • {user.name.name} {user.name.patronomic} {user.name.surname}
  • {user.regestrationDate}
  • {user.status.description}
  • ))}
);

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

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

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

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

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

return (
  
    {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 (
  • {fullName}
  • {date}
  • {user.status.description}
  • ); })}
);

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

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

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

const withVariables = user => callback => {
  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 (
  
    {users.map(withVariables( (user, fullName, date, statusColor) => (
  • {fullName}
  • {date}
  • {user.status.description}
  • ) ))}
);

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

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

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

Спасибо.

© Habrahabr.ru