О чем вам не расскажут на курсах по Реакту. Вредные советы, как стать незаменимым разработчиком

Моя цель - предложение широкого ассортимента товаров и услуг на постоянно высоком качестве обслуживания по самым выгодным ценам.

Если ваша задача — не просто научиться писать код, а понять, как стать тем, без кого поддержка и развитие проекта просто немыслимы, то этот текст для вас. Заодно поговорим о том, как помочь коллегам постичь дзен и досконально изучить структуру разрабатываемого приложения.

Всем привет, меня зовут Макс Кравец, я CEO IT-компании Holyweb, и сегодня хочу поделиться вредными советами о том, как стать незаменимым React-разработчиком. Поехали!

Волшебный спред-оператор 

Вам поставили задачу написать компонент, приветствующий пользователя. Нет ничего легче — обращаемся к объекту, который хранит имя и фамилию, и добавляем их к приветствию:

export function Welcome({name, surname}) {
  return (
    <div>
      Привет, {name} {surname}
    </div>
  )
}

Но на странице приветствие выводится в составе другого компонента, предположим, это хедер. А значит — нужно пробросить параметры. Как поступит новичок? Сядет и методично распишет все в коде родителя:

export function Header({ user }) {
  return (
    <div>
      <Welcome 
        name={user.name}
        surname={user.surname}
      />
      <div>
        Some other code...
      </div>
    </div>
  );
}

В целом — это работает. Но такой код разберет любой другой новичок, ведь движение пропсов по древу компонентов прозрачно! Кроме того, параметров может быть не два, а два десятка. Представляете, сколько времени придется потратить, сколько строк кода написать?

Ловите лайфхак:

export function Header({ user }) {
  return (
    <div>
      <Welcome {...user}/>
      <div>
        Some other code...
      </div>
    </div>
  );
}

Магия спред-оператора — код стал проще, короче, не нужно расписывать каждый параметр. А главное — никто, кроме вас, теперь не может при беглом взгляде на хедер понять, какие именно поля из объекта user на самом деле нужны в компоненте приветствия. 

Вот таким нехитрым способом можно и время сэкономить, и +100 в скилл «незаменимость» себе добавить — пусть только попробуют от вас избавиться, себе дороже выйдет! 

Техника Props Drilling 

Если писать код, беспокоясь только о реализации бизнес-логики, можно даже не заметить, как попадешь в ловушку. 

Простейшая задача: пишем составной компонент, который выводит в банковском приложении информацию о счете клиента. Тип счета задается на верхнем уровне, а отрисовывает его компонент в глубине иерархии. Создаем контекст, определяем провайдер, присваиваем значение…

export const AccountType = createContext()

export function TopComponent() {
  return (
    <AccountType.Provider value="credit">
      <MiddleComponent />
    </AccountType.Provider>

  );
}

export function MiddleComponent() {
  return (
    <LowComponent />
  );
}

export function LowComponent() {
  return (
    <DeepComponent />
  );
}

export function DeepComponent() {
  const accountType = useContext(AccountType);

  return (
    <span> {accountType} account</span>
  );
}

Код выше — воплощение цифрового эгоизма. Судите сами — вашему коллеге достаточно разобраться, где контекст провайдится, и где выводится. А вся остальная иерархия остается без внимания. Хорошо, когда все нужные компоненты выстроены в одном файле друг за дружкой, но где вы такое в реальном проекте видели? 

На помощь приходит техника Props Drilling — просто объявите нужное свойство на самом верху древа компонентов и методично прокиньте до места использования.

export function TopComponent() {
  const account = {
    accountType: "credit"
  }

  return (
      <MiddleComponent account={account} />
  );
}

export function MiddleComponent({account}) {
  return (
    <LowComponent account={account} />
  );
}

export function LowComponent({account}) {
  return (
    <DeepComponent account={account}/>
  );
}

export function DeepComponent({account}) {

  return (
    <span> {account.accountType} account</span>
  );
}

Бинго! Даже если компоненты разнесены по разным папкам проекта, ни один не останется без внимания ваших коллег в процессе поиска возможной ошибки. А чтобы не бросать и этот процесс на самотек и гарантированно заработать искреннюю благодарность соратников по работе, можно где-то в середине цепочки изменить или даже обнулить свойство:

…
export function MiddleComponent({account}) {

  account.accountType = null

  return (
    <LowComponent account={account} />
  );
}
…

Простыми компонентами никого не удивишь

Ну вот и пришло время для серьезной задачи: готовим компонент, который выводит данные карты пользователя приложения. При этом номер карты и CVV по умолчанию должны быть скрыты и отображаться при клике/тапе по соответствующему полю, ФИО — отображаться в виде «имя сокращено до одной буквы, фамилия полностью, все заглавными буквами». Кроме того, нужно предусмотреть возможность копирования номера карты и CVV в буфер обмена.

Сначала пройдем по простому пути, а потом разберем, в чем была ошибка. Напишем функцию, которая будет отправлять нужные данные в буфер обмена

const copyToClipBoard = data => {
  const textField = document.createElement('textarea')
  textField.innerText = data
  document.body.appendChild(textField)
  textField.select()
  document.execCommand('copy')
  textField.remove()
  alert('Скопировано в буфер обмена')
}

добавим разбиение номера карты на группы

const formatNumber = cardNumber => {
  let cNumToStr = ''
    let it = 0
  
  String(cardNumber).split('').forEach((s) => {
    if (it % 4 === 0) {
      cNumToStr = cNumToStr + ' '
    }
    cNumToStr = cNumToStr + s
    it++
  })
  return cNumToStr
}

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

export function CardNumberComponent({cardNumber}) {
  const [isShow, setIsShow] = useState(false)
  
  const toggle = () => {setIsShow(!isShow)} 
  
  const showNumber = isShow 
    ? formatNumber(cardNumber)
    : "•••• " + formatNumber(cardNumber).substring(formatNumber(cardNumber).length - 4)

  return (
    <div>
      <p>Номер карты</p>
      <div onClick={toggle}> {showNumber} </div>
      <button onClick={() => copyToClipBoard(cardNumber)}>копировать</button>
    </div>
  )
}

аналогичным образом разберемся с CVV

export function CardCVVComponent({cvv}) {
  const [isShow, setIsShow] = useState(false)
  
  const toggle = () => {setIsShow(!isShow)} 

  const showCVV = isShow
    ? cvv
    : "•••"
    
  return (
    <div>
      <p>CVV</p>
      <div onClick={toggle}> {showCVV} </div>
      <button onClick={() => copyToClipBoard(cvv)}>копировать</button>
    </div>
  )
}

Напишем компонент, который выводит срок действия карты

export function CardExpireComponent({expire}) {
  return (
    <div>
      <p>Срок действия</p>
      {expire.year}/{expire.month}
    </div>
  )
}

и данные владельца

export function CardUserNameComponent({user}) {
  const userInfo = (user.name[0] + '. ' + user.surname).toUpperCase()

  return (
    <div>
      <p>Владелец</p>
      <div>{userInfo}</div>
      <button onClick={() => copyToClipBoard(userInfo)}>копировать</button>
    </div>
  )
}

Ну и последним действием соберем все вместе

export function CardComponent() {

  return (
    <>
      <CardNumberComponent cardNumber={cardInfo.cardNumber}></CardNumberComponent>
      <CardExpireComponent expire={cardInfo.expire}></CardExpireComponent>
      <CardCVVComponent cvv={cardInfo.cvv}></CardCVVComponent>
      <CardUserNameComponent user={user}></CardUserNameComponent>
    </>
  )
}

Источниками данных будут служить объект информации о пользователе и объект информации о карте

const user = {
  name: 'Ivan',
  surname: 'Ivanov',
}

const cardInfo = {
  cardNumber: "1234567812345678",
  expire: {
    year: 24,
    month: 11
  },
  cvv: 123
}

Как говорится — получите, распишитесь. Но присмотритесь внимательно, что мы накодили в результате? Пара простых функций, несколько небольших компонентов. Срамота, да и только! Этим не похвастаешься перед коллегами, да и начальству не объяснишь, что задача была трудна и неплохо бы подумать о премии. 

Выход — вспомнить о том, что нас просили сделать компонент, который выводит данные о карте. Один. Давайте исправим наш код.

export function CardComponent() {

  const copyToClipBoard = data => {
    const textField = document.createElement('textarea')
    textField.innerText = data
    document.body.appendChild(textField)
    textField.select()
    document.execCommand('copy')
    textField.remove()
    alert('Скопировано в буфер обмена')
  } 
  
  const [isShowNumber, setIsShowNumber] = useState(false)
  const [isShow, setIsShow] = useState(false)
  const toggleNumber = () => {setIsShowNumber(!isShowNumber)} 
  const toggleCVV = () => {setIsShow(!isShow)} 
  const userInfo = (user.name[0] + '. ' + user.surname).toUpperCase()
  let cNumToStr = ''
  let it = 0
  
  String(cardInfo.cardNumber).split('').forEach((s) => {
    if (it % 4 === 0) {
      cNumToStr = cNumToStr + ' '
    }
    cNumToStr = cNumToStr + s
    it++
    return cNumToStr
  })
  
  const showNumber = isShowNumber 
    ? cNumToStr
    : "•••• " + cNumToStr.substring(cNumToStr.length - 4)

  const showCVV = isShow
    ? cardInfo.cvv
    : "•••"
   
  return (
    <>
      <div>
        <p>Номер карты</p>
        <div onClick={toggleNumber}> {showNumber} </div>
        <button onClick={() => copyToClipBoard(cardInfo.cardNumber)}>копировать</button>
      </div>
      <div>
        <p>Срок действия</p>
        {cardInfo.expire.year}/{cardInfo.expire.month}
     </div>
     <div>
       <p>CVV</p>
       <div onClick={toggleCVV}> {showCVV} </div>
       <button onClick={() => copyToClipBoard(cardInfo.cvv)}>копировать</button>
     </div>
     <div>
        <p>Владелец</p>
        <div>{userInfo}</div>
        <button onClick={() => copyToClipBoard(userInfo)}>копировать</button>
    </div>

    </>
  )
}

Согласитесь, выглядит гораздо солиднее? Мало того, что весь функционал в одном месте, так еще и можно быть уверенным — проще будет позвать вас, как автора, чем разобраться, что в этом компоненте к чему относится. А значит — смело можно добавлять +500 в скилл «незаменимость».

Что в итоге?

Разумеется, секретов у настоящего мастера много, и выше приведены далеко не все. Ищите сами, добавляйте свои варианты в комментарии. Но помните, что при этом главное — не перегнуть палку. А то можно стать настолько незаменимым, что никто и на работу взять не рискнет.

Если хотите продолжения, пишите в комментарии или мне в Телеграм, и мы выпустим продолжение подборки незаменимых советов для реакт-мастеров :) 

Другие наши статьи: 

  • Security с характером, или еще несколько слов о паттерне Singleton

  • Как выдать Золушку за принца и не сойти с ума. Паттерн Декоратор

  • Погружение во внедрение зависимостей (DI), или как взломать Матрицу

  • Хаммер-дроны, или фабричный метод в действии

  • Прекратите изучать фреймворк, станьте JavaScript-разработчиком

  • DOM, который построил Chrome. Или не построил? Или не Chrome? Или не DOM?

Источник: https://habr.com/ru/post/650131/


Интересные статьи

Интересные статьи

Syn ack, Хабр!Статья Что делать, когда преследует бывший… работодатель? очень хорошо была воспринята айти сообществом. Та самая статья набрала более чем в 2 раза больше просмотров,и это благодаря ваше...
За последний год мир заполонили всевозможные курсы и онлайн-конференции. Все предлагают поднять свой уровень до сеньора и переквалифицировать в айтишника кого угодно: от ...
Одним тёплым вечером жена сказал что стала владельцем нашим Музеем Мирового океана, находящимся в Калининграде. Она просто нажала на кнопку "Я владелец компании" в Google...
Всем привет. Когда я искал информацию о журналировании (аудите событий) в Bitrix, на Хабре не было ни чего, в остальном рунете кое что было, но кто же там найдёт? Для пополнения базы знаний...
Привет, Хабр! Начав изучение Scala, я сразу столкнулся с тем, что функциональная реализация простейшего алгоритма быстрой сортировки работает радикально медленней и потребляет существенно боль...