채팅방을 생성하는 모달입니다. 현재 게시물에선 해시태그를 어떻게 구현했는지에 대해서 설명할것이기 때문에 해시태그 관련된 코드만 어떻게 구현했는지에 대해 설명하겠습니다.
const [tag, onChangeTag, reset] = useInput('');
const [tagList, setTagList] = useState<string[]>([]);
<HashTagInput
onChangeTag={onChangeTag}
reset={reset}
setTagList={setTagList}
tag={tag}
tagList={tagList}
/>
해시태그를 관리하는 컴포넌트입니다.
tag : 현재 input의 입력된 value
onChangeTag : value 변환시 계속 업데이트해주는 함수
reset : value 초기화 함수
tagList : 태그 리스트를 관리하는 string 배열의 상태
setTagList: 태그 리스트 상태변경해주는 상태변경함수.
input의 value값은 커스텀훅인 useInput을 사용하여 관리하였습니다.
import { ChangeEvent, useState } from 'react';
const useInput = (initialValue: string) => {
const [value, setValue] = useState(initialValue);
const onChangeValue = (
e: ChangeEvent<HTMLInputElement | HTMLTextAreaElement>,
) => {
setValue(e.target.value);
};
const resetValue = () => {
setValue('');
};
return [value, onChangeValue, resetValue] as const;
};
export default useInput;
다음은 HashTagInput 컴포넌트의 내부를 살펴 보겠습니다.
<div className="flex flex-wrap items-center w-full ">
<div className="flex flex-wrap items-center flex-1 gap-2 overflow-auto max-h-20">
{tagList.map((tagItem) => (
<div
key={tagItem}
onClick={() => removeTagByName(tagItem)}
className="cursor-pointer animate-scaleUp"
>
<Tag tagName={tagItem} />
</div>
))}
<input
type="text"
onChange={onChangeTag}
className={`p-0 border-none w-72 tablet:w-96 focus:ring-0 body1 ${
isHashTagNumOver ? 'placeholder:text-red' : ''
}`}
placeholder={
isHashTagNumOver
? '해시태그는 10개를 초과할 수 없어요.🥲'
: '#해시태그를 이용해서 채팅방을 소개해 보세요'
}
value={tag}
onKeyUp={addTagByEnter}
onKeyDown={removeTagByBackspace}
/>
</div>
<div className="caption2 text-grey-400">{tagList.length}/10</div>
</div>
해당 컴포넌트의 큰 기능은 다음과 같습니다.
- 해시태그로 사용하고싶은 단어를 입력후 Enter를 누르면 해시태그가 추가되고 보여야한다.
- 해시태그를 지우고싶을때 특정 해시태그를 클릭하면 해당 해시태그는 제거 되어야한다.
- Backspace를 이용하여 해시태그를 지울수 있어야한다.
Enter 입력시 해시태그 추가
const isHashTagNumOver = tagList.length >= 10;
const addTagByEnter = (event: KeyboardEvent) => {
const isDuplicateTag = !tagList.includes(tag);
const isNonEmptyTag = tag.trim() !== '';
if (event.key === 'Enter') {
if (isDuplicateTag && isNonEmptyTag && !isHashTagNumOver) {
setTagList([...tagList, tag]);
reset();
}
}
};
이미 입력되어있는 태그와 아무것도 입력하지 않았을때를 변수로 만들어주었습니다. 또한 해시태그가 이미 10개이상 추가되어있다면 추가가 안되게끔 막아주었습니다.
특정 해시태그 제거
const removeTagByName = (name: string) => {
const filteredTagList = tagList.filter((tagName) => tagName !== name);
setTagList(filteredTagList);
};
{tagList.map((tagItem) => (
<div
key={tagItem}
onClick={() => removeTagByName(tagItem)}
className="cursor-pointer animate-scaleUp"
>
<Tag tagName={tagItem} />
</div>
))}
클릭했을때의 태그이름과 현재 저장되어있는 태그들을 비교하여 새로운 배열로 반환하여 상태로 다시 저장하여 특정 태그를 제거하는 기능을 구현하였습니다.
Backspace 입력시 마지막 태그 제거
const removeTagByBackspace = (event: KeyboardEvent) => {
const isTagListNotEmpty = tagList.length >= 1; // 태그리스트에 1개 이상의 태그가 있다면
const isTagValueEmpty = tag.length === 0; // 태그 추가를 위한 value가 없다면
if (event.key === 'Backspace' && isTagListNotEmpty && isTagValueEmpty) {
const lastTag = tagList.at(-1);
const removedTagList = tagList.filter((tagName) => tagName !== lastTag);
setTagList(removedTagList);
}
};
유저가 Backspace 입력을 한다는것은 두가지의 조건이 있습니다.
1. 태그 추가를 위해 유저가 input 에 value를 넣은경우
2. 마지막 태그를 지우기 위한 경우
해당 조건들은 변수로 만들어 사용하였습니다.
모든 조건을 충족했다면 현재 태그리스트의 마지막요소를 특정하기위해 Array.at() 메서드를 사용하여 마지막 요소를 특정하였습니다.
특정된 태그를 다시 현재태그리스트와 비교하여 특정된태그를 제외한 새로운 배열을 반환하여 상태저장 해주었습니다.
결과물
'React' 카테고리의 다른 글
React-Query - onClick 이벤트로 useQuery data fetching (0) | 2023.10.09 |
---|---|
React- 재사용성과 확장성을 높이는 리액트 컴포넌트 설계 하기 (1) | 2023.09.25 |
리액트 라이브러리없이 달력(Calender) 구현 with "date-fns" (0) | 2023.09.12 |
React - useCallback, useMemo 에 대하여 (0) | 2023.07.04 |
React - React-hook-form 회원가입시 닉네임 중복검사 하는법 (0) | 2023.06.05 |