코드를 줄여보자 - ChoDragon9/posts GitHub Wiki

레이어팝업 노출을 위한 상태와 함수를 줄여보자

레이어팝업 노출하기 위해서는 최소한 한개씩 변수와 함수가 필요하다.

export class AppComponent {
  isShow = false;
  toggle() {
    this.isShow = !this.isShow;
  }
}
<div>
  <button
    type="button"
    (click)="toggle()"
    *ngIf="!isShow">Open</button>
  <div *ngIf="isShow">
    <button
      type="button"
      (click)="toggle()">Close</button>
    <ul>
      <li><a href="#">Menu1</a></li>
      <li><a href="#">Menu2</a></li>
    </ul>
  </div>
</div>

하지만 복잡한 UI 일수록 많은 레이어팝업이 있고, 그만큼 상태와 함수가 늘어나기 때문에 이 코드를 줄일 수 없을 까 하고 고민했다. 레이어팝업 3개만 있어도 아래 갯수만큼 늘어난다.

export class AppComponent {
  isShow1 = false;
  toggle1() {
    this.isShow1 = !this.isShow1;
  }
  isShow2 = false;
  toggle2() {
    this.isShow2 = !this.isShow2;
  }
  isShow3 = false;
  toggle3() {
    this.isShow3 = !this.isShow3;
  }
}
<div>
  <button
    type="button"
    (click)="toggle1()"
    *ngIf="!isShow1">Open</button>
  <div *ngIf="isShow1">
    <button
      type="button"
      (click)="toggle1()">Close</button>
    <ul>
      <li><a href="#">Menu1</a></li>
      <li><a href="#">Menu2</a></li>
    </ul>
  </div>
</div>

<div>
  <button
    type="button"
    (click)="toggle2()"
    *ngIf="!isShow2">Open</button>
  <div *ngIf="isShow2">
    <button
      type="button"
      (click)="toggle2()">Close</button>
    <ul>
      <li><a href="#">Menu1</a></li>
      <li><a href="#">Menu2</a></li>
    </ul>
  </div>
</div>

<div>
  <button
    type="button"
    (click)="toggle3()"
    *ngIf="!isShow3">Open</button>
  <div *ngIf="isShow3">
    <button
      type="button"
      (click)="toggle3()">Close</button>
    <ul>
      <li><a href="#">Menu1</a></li>
      <li><a href="#">Menu2</a></li>
    </ul>
  </div>
</div>

공통적인 특징은 불값을 가진 상태와 토글할 수 있는 함수이다. 상태와 함수를 클래스로 만들어 위임받아 사용하면 중복된 코드를 삭제할 수 있다!!

export class AppComponent {
  layer1 = new LayerHelper();
  layer2 = new LayerHelper();
  layer3 = new LayerHelper();
  constructor() {}
}

class LayerHelper {
  isShow = false;
  toggle() {
    this.isShow = !this.isShow;
  }
  constructor() {}
}
<div>
  <button
    type="button"
    (click)="layer1.toggle()"
    *ngIf="!layer1.isShow">Open</button>
  <div *ngIf="layer1.isShow">
    <button
      type="button"
      (click)="layer1.toggle()">Close</button>
    <ul>
      <li><a href="#">Menu1</a></li>
      <li><a href="#">Menu2</a></li>
    </ul>
  </div>
</div>

<div>
  <button
    type="button"
    (click)="layer2.toggle()"
    *ngIf="!layer2.isShow">Open</button>
  <div *ngIf="layer2.isShow">
    <button
      type="button"
      (click)="layer2.toggle()">Close</button>
    <ul>
      <li><a href="#">Menu1</a></li>
      <li><a href="#">Menu2</a></li>
    </ul>
  </div>
</div>

<div>
  <button
    type="button"
    (click)="layer3.toggle()"
    *ngIf="!layer3.isShow">Open</button>
  <div *ngIf="layer3.isShow">
    <button
      type="button"
      (click)="layer3.toggle()">Close</button>
    <ul>
      <li><a href="#">Menu1</a></li>
      <li><a href="#">Menu2</a></li>
    </ul>
  </div>
</div>

async, await + Promise.all

async, await를 사용하여 동기코드와 유사하게 코드 작성이 가능하다. 여기에 Promise.all를 사용하면 병렬처리를 구현할 수 있다. 아래와 같이 일정시간이 지나면 resolve를 실행해는 delay함수가 있다.

const delay = (ms) => new Promise((resolve) => setTimeout(() => resolve(ms), ms));

Promise를 리턴하는 함수를 사용할 때 await를 통해 resolve값을 받을 수 있다. main 함수의 결과는 6005ms 뒤에 반환된다.

const main = async () => {
  console.time('main');
  const delay1s = await delay(1000);
  const delay2s = await delay(2000);
  const delay3s = await delay(3000);
  console.timeEnd('main');
  return delay1s + delay2s + delay3s;
};
main().then(console.log);
// main: 6005.81787109375ms
// 6000

각각의 Promise들이 서로 영향이 없다면 병렬로 처리할 필요가 있다. 모든 Promise가 끝날 때 Promise.all를 통해 확인한다. 함수의 결과는 3005ms 뒤에 반환된다. 병렬 처리를 하게 되면 빠른 응답을 받을 수 있다.

const main = async () => {
  console.time('main');
  const [delay1s, delay2s, delay3s] = await Promise.all([delay(1000), delay(2000), delay(3000)]);
  console.timeEnd('main');
  return delay1s + delay2s + delay3s;
};
main().then(console.log);
// main: 3001.468017578125ms
// 6000

등록시간과 현재시간 비교 후 N개월 N일 표시

moment 라이브러리를 사용하여 f(등록시간, 현재시간) = N일{diffDays < 30), N개월 N일{diffDays >= 30} 표시 구현을 해보자.

const current = moment([2018, 11, 28]);
const createdAt = moment([2018, 10, 2]);

moment(createdAt).format('YYYY.MM.DD'); // 2018.11.2, 월은 0부터 시작

moment#diff만으로는 정확한 일을 구할 수가 없다. days 옵션은 총 일수를 반환하기 때문에 원한은 값을 얻을 수 없다.

console.log(
  current.diff(createdAt, 'month'),
  current.diff(createdAt, 'days'),
); // 1 56

moment#duration 기능을 사용하면 지난 개월수와 일수을 반환해준다.

const duration = moment.duration(current.diff(createdAt));
console.log(duration.months(), duration.days()); // 1 25

함수를 구현하면 아래와 같다.

const current = 1545922800000; //moment([2018, 11, 28]);
const createdAt = 1541084400000; //moment([2018, 10, 2]);

const diff = (srcTimestamp, targetTimestamp) => {
  const duration = moment.duration(moment(srcTimestamp).diff(moment(targetTimestamp)));
  const diffDay = duration.days();
  if (duration.asDays() < 30) {
    return `${diffDay}일`;
  } else {
    return `${duration.months()}개월 ${diffDay}일`;
  }
};

console.log(diff(current, createdAt)); // 1개월 25일
⚠️ **GitHub.com Fallback** ⚠️