* React, Styled-Component, Storybook을 활용한 UI 컴포넌트 개발
* Styled Components를 활용해 Tag 커스텀 컴포넌트를 구현
Tag Component
완성 예시
Tag UI 컴포넌트는 레이블 지정을 통해 구성이나 분류에 도움이 되는 키워드 집합을 만들 때 사용된다.
필요한 컴포넌트
TagInput (div) : Tag 최상위 박스
- ul id "tags"
- li className "tag" : 각각의 tag 박스 (나열)
- span className "tag-title"
- span className "tag-close-icon"
- li className "tag" : 각각의 tag 박스 (나열)
- input className "tag-input" : tag를 입력하여 추가하는 구역
state
- Tag 컴포넌트는 아래와 같은 state가 존재한다.
- tags state : 배열의 형태로 초깃값으로 initialTags를 가지고 있다. (예: ["Doyu", "React", "Layout"])
- (1) 태그를 추가하기 위한 핸들러 함수 addTags는 새로운 태그값을 입력하는 칸에 넣어준다.
- addTags 함수 :
- input 창에 Enter 키를 누를 때 발생되는 change 이벤트 핸들러
- Enter를 입력할 때마다 입력한 값이 state에 추가
- addTags 함수 :
- (2) 태그를 삭제하기 위한 핸들러 함수 removeTags는 개별 태그 박스 안의 (X) 버튼에 달아준다.
- removeTags 함수 :
- 태그 박스 안의 (X) 버튼을 누를 때 발생되는 click 이벤트 핸들러
- 클릭을 할 때 마다 해당 태그와 관련된 값이 state에서 삭제
- removeTags 함수 :
구현 코드
Tag UI Component 코드
import { useState } from 'react';
import styled from 'styled-components';
export const TagsInput = styled.div`
margin: 8rem auto;
display: flex;
align-items: flex-start;
flex-wrap: wrap;
min-height: 48px;
width: 480px;
padding: 0 8px;
border: 1px solid rgb(214, 216, 218);
border-radius: 6px;
> ul {
display: flex;
flex-wrap: wrap;
padding: 0;
margin: 8px 0 0 0;
> .tag {
width: auto;
height: 32px;
display: flex;
align-items: center;
justify-content: center;
color: white;
padding: 0 8px;
font-size: 14px;
list-style: none;
border-radius: 6px;
margin: 0 8px 8px 0;
background: #0000f1;
> .tag-close-icon {
display: block;
width: 16px;
height: 16px;
line-height: 16px;
text-align: center;
font-size: 14px;
margin-left: 8px;
color: var(--coz-purple-600);
border-radius: 50%;
background: #fff;
cursor: pointer;
}
}
}
> input {
flex: 1;
height: 46px;
font-size: 14px;
padding: 4px 0 0 0;
:focus {
outline: transparent;
}
}
&:focus-within { // "&"는 TagsInput 나타내는 선택자 (자기자신)
border: 1px solid purple;
}
`;
export const Tag = () => {
const initialTags = ['Doyu', 'kimcoding'];
const [tags, setTags] = useState(initialTags);
const removeTags = (indexToRemove) => {
setTags( tags.filter( (_,idx) => idx !== indexToRemove )); // 첫 번째 인자를 안 쓰는 경우 '_' 기호 사용
};
const addTags = (event) => {
if (event.target.value && !tags.includes(event.target.value)) { // - 이미 입력되어 있는 태그인지 검사하여 이미 있는 태그라면 추가하지 말기
// console.log(typeof event.target.value) // - 아무것도 입력하지 않은 채 Enter 키 입력시 메소드 실행하지 말기
setTags([...tags, event.target.value])
event.target.value = ''; // - 태그가 추가되면 input 창 비우기
}
};
// typeof event.target.value 는 'string'이다. ('0' 등의 숫자를 입력해도)
return (
<>
<TagsInput>
<ul id="tags">
{tags.map((tag, index) => (
<li key={index} className="tag">
<span className="tag-title">{tag}</span>
<!--'HTML Entities' 중 하나인 &Times;는 X 곱하기 부호를 나타낸다. -->
<span className="tag-close-icon" onClick={() => removeTags(index)}>×</span>
</li>
))}
</ul>
<input
className="tag-input"
type="text"
onKeyUp={ e => {if(e.key === 'Enter') addTags(e)}}
<!-- 또는 onKeyUp={(e) => (e.key === 'Enter' ? addTags(e) : null)} -->
placeholder="Press enter to add tags"
/>
</TagsInput>
</>
);
};
포인트
🟣 onKeyup
onkeyup (KeyCode 값) : 사용자가 키보드의 키를 눌렀을 때
- value(텍스트)가 입력된 후 이벤트가 실행된다.
- 예: 'Hi!' 에서 'H'를 누르고 난 후 value : 'H'
onkeydown (KeyCode 값) : 사용자가 키보드의 키를 눌렀다가 땔 때
- value(텍스트)가 입력되기 전에 이벤트가 실행된다.
- 예: 'Hi!' 에서 'H'를 누르고 난 후 value : ''
onkeypress (ASCII 값) : 사용자가 키보드의 키를 눌렀을 때
- value(텍스트)가 입력되기 전에 이벤트가 실행된다.
- 예: 'Hi!' 에서 'H'를 누르고 난 후 value : ''
- shift, ctrl 등의 key 인식 못 함
🟣 event.key 와 event.code
event.key : 사용자가 실제 키보드 키를 나타내는 문자열 값 반환
- 예: 'A', 'Enter', 'Backspace', '1' ....
- 한국어 키보드를 사용하면 'ㅁ' 과 같이 한글 문자열을 반환할 수 있다.
event.code : 사용자가 누른 키보드 키의 물리적 위치를 나타내는 문자열 값 반환
- 예: 'KeyA', 'Enter', 'Backspace', 'Digit1'
- 사용자가 어떤 키보드 레이아웃을 사용하든 동일한 값을 반환한다.
* event.keyCode는 더이상 지원되지 않는 기술이므로 사용하지 않는다.
콘솔로 직접 찍어보면 더 이해가 잘 간다.
console.log(`e.key : ${e.key} , e.code : ${e.code}`);
728x90
'FE > React' 카테고리의 다른 글
[React] 전역 상태의 필요성 (0) | 2023.04.21 |
---|---|
Styled Components로 ClickToEdit 만들기 (0) | 2023.04.20 |
Styled Components로 Tab 만들기 (0) | 2023.04.20 |
Styled Components로 Toggle 만들기 (0) | 2023.04.20 |
Styled Components로 Modal 만들기 (0) | 2023.04.20 |