2019 IBM Developer Day(https://developer.ibm.com/kr/devday2019/) 에서 재사용 가능한 커스텀 컴포넌트를 만드는 이야기에 관하여 발표한 자료입니다.
---
발표 소개: 여러분은 어디든 쉽게 끼울 수 있는 블록을 만들어야 합니다. 하지만 그 블록은 조금의 노력으로 많은 일을 할 수 있어야 하고 / 쉽게 개조할 수 있어야 하고 / 다른 블록과 같은 규칙을 따라야 하며 / 무엇보다도 쓰기 편하고 예뻐야 합니다. 이는 보통의 프런트엔드 개발자가 재사용 가능한 컴포넌트를 만들 때 하는 고민입니다. 본 발표에서는 데이터 사이언스 노트북 플랫폼 Zepl의 UI를 전면 개편하며 만들었던 커스텀 컴포넌트의 디자인부터 구조 설계, 리팩토링에 관해 이야기를 합니다.
2. 발표 개요
2
1. 들어가며
2. 프런트엔드: 상호작용과 상태
3. 컴포넌트
4. 재사용 가능한 컴포넌트 만들기 A to Z
5. 마무리
3. 발표 목표
3
1. 웹 프런트엔드에 익숙하지 않았던 사람은?
→ 프런트엔드의 상태, 상호작용, 그리고 컴포넌트에 대해 설명할 수 있다
2. 자바스크립트 개발은 알지만 리유저블 컴포넌트에 익숙하지 않은 사람은?
→커스텀 리유저블 컴포넌트를 탄탄하게 설계할 수 있게 된다
3. 리유저블 컴포넌트에 이미 익숙한 사람은?
→다른 회사의 사례를 참고하며 지금까지 만들었던 컴포넌트 설계를 검토할
수 있다
9. 논문 공유 서비스 v1.0.0
9
상태
1. 논문 내용
상호작용
1. 논문 내용 받아오기
nonmun.com/nonmun-id-123
논문 제목제목
논문 내용이랍니다 내용이 깁니다. 논문 내용
이랍니다 내용이 깁니다. 논문 내용이랍니다
내용이 깁니다. 논문 내용이랍니다 내용이 깁
니다.
김뫄뫄, 장뫄뫄
사용자 눈에 보이는 데이터 사용자와 웹의 상호작용
10. 논문 공유 서비스 v2.0.0
10
nonmun.com/nonmun-id-123
23 likes
사용자 눈에 보이는 데이터 사용자와 웹의 상호작용
논문 제목제목
논문 내용이랍니다 내용이 깁니다. 논문 내용
이랍니다 내용이 깁니다. 논문 내용이랍니다
내용이 깁니다. 논문 내용이랍니다 내용이 깁
니다.
김뫄뫄, 장뫄뫄
상태
1. 논문 내용
2. 총 좋아요 수 (23)
3. 내가 좋아요를 눌
렀는가? (true/
false)
상호작용
1. 논문 내용 및 좋아
요 수 받아오기
2. 좋아요를 누른다
3. 좋아요를 취소한다
11. 논문 공유 서비스 v3.0.0
11
nonmun.com/timeline
지금 뜨는 논문
1904
내 논문 리스트
사용자 눈에 보이는 데이터 사용자와 웹의 상호작용
상태
1. 지금 뜨는 논문 리스트
- 제목, 저자, 링크
2. 총 좋아요 수
3. 내 논문 리스트
- 제목, 링크
상호작용
1. 지금 뜨는 논문 받아오기
2. 내 논문 리스트 받아오기
3. 총 좋아요 받아오기
4. 좋아요 수로 논문 정렬
5. 논문 이름으로 검색
12. 상태와 상호작용?
12
상태란 웹이 사용자에게 더욱 풍성하고 동적인 경험을 주기 위하여 저장
하고 있는 사용자 인터랙션 관련 데이터다.
이 상태는 서버의 데이터에서 받아와서 보여주기도 하지만
사용자의 인터랙션에 따라 매 순간 바뀔 수 있어야 한다.
== 프런트엔드 전용 데이터베이스
서버의 좋아요 수 상태: 20
20
좋아요 누르기
인터랙션프런트의 좋아요 수 상태: 20
서버의 좋아요 수 상태: 20
21
프런트의 좋아요 수 상태: 21
서버에
알려주기
서버의 좋아요 수 상태: 21
21
프런트의 좋아요 수 상태: 21
18. 컴포넌트에 상호작용과 상태를 넘기면
18
언제 어디서든 원하는 모양의 일관적인 UI를 쉽게 재사용할 수 있다.
52번 재사용된 Table 컴포넌트 172번 재사용된 Button 컴포넌트
19. 실무에서 사용하는 컴포넌트의 3가지 타입
19
Type 1. 내부에서 처음부터 만든 커스텀 컴포넌트
Type 2. 외부 라이브러리 커스텀 (e.g. datatables, bootstrap)
Type 3. 외부 라이브러리의 마개조 슈퍼-커스텀(원본 UI의 흔적을 찾아볼 수 없
다?!)
20. 재사용 가능한
컴포넌트 만들기 A to Z
20
실무에서 바로 사용하는
컴포넌트 깎는 노인이 되어보자
21. Step 1. 디자인→(상태&액션&UI)
21
1.디자이너가 준 컴포넌트의 디자인을 보고 상태와 액션을 리스트업
2.디자인에 있는 모든 요소를 어떻게 컨트롤할지 적기 (부담x)
3.UI 필요조건 있으면 명시
4.리스트업 완료되면 디자이너와 함께 리뷰
*디자이너가 안 계신 분들은…
22. 디자인→(상태&액션&UI)
22
상태
1.테이블 열 제목 리스트
1.*제목
2.원하는 너비
3.정렬 허용 여부
2.테이블 데이터 리스트
1.*각 행별 데이터
3.데이터 정렬 기준열 이름
4.데이터 정렬 방향
5.데이터가 없을때 보여줄 텍스트
액션
1.테이블 열 제목을 누를때마다 오름/내림차순 정렬
2.정렬을 위한 함수를 따로 넘길 수 있다
UI
1.각 열마다 원하는 너비를 넘길 수 있다
2.*반응형 대응
23. Step 2. 다른 라이브러리 조사
23
1. 다른 라이브러리들은 비슷한 컴포넌트
를 어떤 식으로 만들었는지 조사.
노트를 펴고 간단히 메모하며 조사
- 여기는 이렇게 데이터를 구분했구나
- A 기능을 구현한 방법이 고급스럽다!
벤치마킹해야지
2. 이 때 우리 요구사항에 부합하는 라이
브러리를 찾으면 앗싸 땡큐 하고 쓰면
되나? No!
24. * 외부 라이브러리를 가져다 커스텀할 때 고려할 점
24
✓우리의 요구사항이 잘 구현되어 있나
✓우리의 요구사항에 비해 기능이 너무 많아 무겁진 않은가
✓커스텀하기 편한가? 6개월 후의 나도 무리 없이 커스텀할 수 있는
가?
✓최근까지 유지보수가 활발하게 되고 있는가?
✓혹여 중간에 라이브러리 개발이 중단되더라도 영향 없이 유지보
수를 할 수 있는가?
*웬만하면 모두 충족하는 라이브러리를 찾아야 합니다
25. *사용해도 될 것 같은 라이브러리를 찾으면
쓰기 전에 (웬만하면 꼭) 팀원에게 공유합니다
25
•기존에 쓰던 jQuery 캐러셀을 대체
할 캐러셀(슬라이드) 라이브러리를
조사했다
•우리 요구사항은 1. 반응형 2. 내부
컴포넌트가 교체가능한지 3. jQuery
의존성이 없는지 이다
•react-slick이 제일 유명한데 jQuery
의존성이 있음
•nuka-carousel도 괜찮아보이는데
반응형이 아님
•react-alice-carousel은 신생이지만
모든 요구조건 만족한다.
•이거 쓰려고 하는데 어케 생각하심?
26. Step 3. 사용자의 입장에서 MVP 컴포넌트 설계
26
1.컴포넌트가 이미 구현되어있다 가정하고
Step.1에서 정의한 상태를 key와 value
로 설계 (e.g. columns에 이렇게 생긴 배
열을 넘긴다)
2.TDD와 비슷. 디자인을 보고 코드의 얼개
를 짜는거니 DDD?
3.MVP(최소기능제품)먼저! 조금이라도 부
가적인 기능은 꼭 다음 스텝으로 미루기
4.[MVP] 열 제목 리스트인 columns와 행
데이터 리스트인 dataSource를 상태로
전달
<Table
columns={[
{
title: " ", dataIndex: “title", width: 7,
},
{
title: “ ", dataIndex: “author", width: 3,
},
{
title: " ", dataIndex: “likes", width: 1,
},
]}
dataSource={[
{
key: "n1",
title: " ",
author: " ",
likes: 3,
},
{
key: "n2",
title: " ",
author: " ",
likes: 10,
},
]}
/>
29. 5. 세부 기능 붙이기
29
이제 여러분 마음대로 세부 기능을 붙이세요. 다만 이 기능을 컴포넌트 내부에서 Stateful하
게 구현할지, 아니면 Stateless하게 구현할지 선택해야 합니다.
(정렬할 때 관리해야 하는 상태: 1. 정렬 기준 키(likes) 2. 정렬 방향(asc) 3. 정렬 함수(alphabetically))
A. Stateful (나만의 비밀상태^^)
“쉿, 아무 말 마요. 열 정렬은 알아서 할게요.”
B. Stateless (비밀없다! 상태없다!)
“제가 따로 오름차순인지 내림차순인지 알고있진 않아요…
그냥 위에서 시키는대로 가공 없이 뿌려줄 뿐이에요”
30. A. Stateful 한 Table 컴포넌트
30
//
<Table
columns={[]}
dataSource=[…]
/>
// ( )
const Table = ({columns, dataSource}) => {
const [sortAsc, setSortAsc] = false;
const [sortKey, setSortKey] = “likes”;
return (
<table>
<th onClick={() => setSortAsc(!sortAsc)}>
</th>
{dataSource.sort(sortKey, sortAsc)}
</table>
);
}
어떤 열 기준/방향으로 정렬해야할지 저장하는 ‘상태’를 Table 컴포넌트 내부에 저장
=> 사용할 때 굳이 상태관리를 안해줘도 됨. Table 컴포넌트 내부에 이미 다 들어있으
니. 쓸때는 간단하지만 Table 내부 코드가 상태를 예측하기 힘들고 복잡해짐.
휴먼, 아무 신경 쓰지 마세요.
제가 이미 알아서 하고 있잖아요.
31. B. Stateless 한 Table 컴포넌트
31
//
const [sortAsc, setSortAsc] = false;
const [sortKey, setSortKey] = “likes”;
<Table
dataSource={
dataSourceArray.filterBy({title,
likes}
)}
onClickSort={
selectedKey =>
customSortAction({ selectedKey })
}
sortIndex={sortKey}
sortDirection={sortAsc}
/>
// ( )
const Table = ({columns, dataSource, onClickSort,
sortIndex, sortDirection}) => {
return (
<table>
<th sortDirection={sortDirection}>
</th>
{dataSource.sort(sortKey, sortAsc)}
</table>
);
}
어떤 열 기준/방향으로 정렬해야할지 저장하는 ‘상태’를 쓰는 쪽에서 저장
=> 정렬을 쓸때마다 새로 상태관리를 해줘야함. Table은 위에서 이미 정렬된 데이터를 뿌려주
기만 함. Table 코드가 간단해지고 보여지는 결과 예측이 쉬움.
정렬은 알아서 하시라구요..
전 주신 데이터 그대로만 보여줄라니깡..
32. A(Stateful)가 훨씬 사용하기 편해보이는데,
B(Stateless)처럼 피곤하게 구현하는 이유가 있나요?
32
1.상용 서비스를 만들다보면 한 컴포넌트를 여러 방식/데이터로 쓰
는게 비일비재 => 확장성과 유연함이 정말! 중요
2.A는 암묵적으로 오름차순/내림차순으로만 정렬하는데…
Q. 날짜나 타임스탬프 등 특수한 정렬을 해야 한다면 어떻게?
Q. 정렬될때마다 서버에 동기화해야한다면?
Q. 정렬 기준을 2개 이상 잡고싶다면?
여러 케이스에서 쓸때마다 상태가 복잡하게 바뀐다면, 리유저블 컴포
넌트는 예측이 쉬운 Stateless 컴포넌트로 만드는게 오히려 재사용하
기 좋다.
33. A와 B의 장점을 섞자
33
시키지 않으면 알아서 똑똑하게 정렬하되,
가끔 특이 케이스가 나올때 기능을 유연하게 덮어쓸 수 있도록 추가
적인 옵션을 마련한다!
34. 6. 마지막은, 문서화!
34
모두 고생하셨습니다. 하지만 여기서 끝내시면 ‘재사용 가능한 컴포
넌트'라고 부를 수 없습니다.
막상 만들어두고 문서화를 하지 않으면 무슨 기능이 있는지 까먹어
서 재사용하기 힘드니까요.
(저도 이 발표 준비하면서 테이블 컴포넌트 문서 덕을 톡톡이 봤습니다 제가 만들고 계속
쓰는건데도 맨날 까먹어요)
35. 하지만…생각만 해도 귀찮습니다
35
1. 컴포넌트 자체가 계속 업데이트될텐데
매번 왔다갔다하면서 문서 업데이트하기 힘들거같아요
2. 어떤 툴로 적어야할지 모르겠어요.
일반 텍스트랑 코드를 같이 적을 수 있는 툴이 있나요?
3. 실제 동작하는 예시 코드를 보고싶은데, 가능할까요.
36. 그런 툴이 있다, Storybook!
36
1.Vuepress나 Docusaurus처럼
스태틱한 다큐멘테이션 사이트
를 만들어준다
2.웹사이트에서 쓰는것처럼
storybook파일에 컴포넌트 코드
를 넣으면 실제 컴포넌트를 조작
해보고 예시코드도 볼 수 있다.
3.리액트, 뷰, 앵귤러 혹은 일반
HTML 등 다양한 환경 지원
39. Recap! 커스텀 컴포넌트를 만드는 5단계
39
1. 디자인을 컴포넌트 명세서로 바꾼다: 1. 상태, 2. 액션, 3. UI
2. 외부 라이브러리를 가져다 커스텀할지 혹은 직접 새로 만들지 결
정한다. 최소 6개월 앞을 생각해봐야한다.
3. TDD와 같이 컴포넌트 껍데기를 먼저 만든 후 내부를 구현한다
4. 컴포넌트가 Stateful할지, Stateless할지 결정한다
5. Storybook 같은 동적 툴로 문서화를 한다
40. 실무에서 컴포넌트 만드는 썰썰썰!
40
Case 1.
외부 라이브러리 커스텀하기
Case 2.
커스텀 컴포넌트가 2살이 되었을 때…
밉다…
곱다…
41. 미우고 고운 제 컴포넌트 새끼덜… 보시겠어요?
41
부모의 마음 ㅎㅎ
Skeleton
Select
Button
Table
InlineSearch
Carousel
SearchableSelect