카드의 태그 관련 이슈가 발생했습니다.
카드 생성 POST API에 태그 색상과 관련된 속성이 없어서 생긴 문제인데 확인해 보겠습니다.
🚫 문제 상황
화면이 리렌더링 될 때마다 태그의 색상이 랜덤 하게 변경됩니다.
카드를 생성하는 POST API에 태그 색상에 대한 옵션이 없어서 발생한 문제입니다.
처음 작업할 때 태그 컴포넌트가 렌더링 될 때 정해진 5개 색상 중 랜덤하게 설정되도록 만들었거든요...😅
const getTagColor = (styles: Record<string, string>): string => {
if (!bgTag || bgTag.length === 0) return '';
const idx = Math.floor(Math.random() * bgTag.length);
return styles[bgTag[idx]];
};
function Chip({ children, chipType }: PropsWithChildren<ChipProps>) {
const className = clsx(
styles[chipType],
chipType === 'tag' && getTagColor(styles),
);
return (
<span className={className}>
{children}
</span>
);
}
스크럼 회의 때 많은 논의를 했고 결론이 나진 않았지만, 다음과 같은 의견들이 나왔습니다.
- 태그의 배경 색상을 제거하자.
- 카드 정보를 Redux로 전역 관리하자.
- CSS의 nth-child() 선택자로 태그의 순서에 따라 색상을 결정하자.
의견이 좁혀지지 않았고, 그 이유는 다음과 같았습니다.
- 태그의 배경 색상을 제거하면 기획 요건을 충족하지 못하니 기획서대로 구현하자.
- 카드 정보를 Redux로 전역 관리하는 것은 불필요한 리소스를 증가시키는 것 같다.
- CSS의 nth-child() 선택자를 사용하면, 태그를 삭제하면 색상이 변경되어 일관성이 없는 것 같다.
💡 해결 방법
현재 태그(Chip 컴포넌트)가 렌더링 될 때 랜덤으로 색상을 생성하는 유틸 함수를 이용하면 될 것 같다는 아이디어가 생각나서 팀원분들께 적용해 보겠다고 말씀드렸습니다😄
서버에 카드 생성(POST) 요청을 보낼 때 태그만 보내는 것이 아니라 태그에 색상을 추가해서 보내는 것입니다.
간단히 말하자면 태그를 생성하면 태그 문자열 뒤에 랜덤 한 색상을 추가하는 거죠!
Chip 컴포넌트
const getTagColor = (): string => {
if (!bgTag || bgTag.length === 0) return '';
const idx = Math.floor(Math.random() * bgTag.length);
return bgTag[idx];
};
function Chip({ children, chipType, color }: PropsWithChildren<ChipProps>) {
const className = clsx(styles[chipType], chipType === 'tag' && styles[color]);
return (
<span className={className}>
{children}
</span>
);
}
기존 Chip 컴포넌트와 다르게 color를 props로 받아오게 수정했습니다.
태그(Chip 컴포넌트)를 렌더링 하는 페이지들도 수정해 보겠습니다.
Chip 컴포넌트 렌더링 페이지
const handleTagInput = (e: React.ChangeEvent<HTMLInputElement>) => {
const newTag = e.target.value.trim();
const color = getTagColor();
const coloredTag = `${newTag} ${color}`;
if (!newTag || tags.includes(newTag)) return; // 빈 문자열 또는 중복 태그 방지
onAddTag(coloredTag);
e.target.value = '';
};
- const coloredTag = `${newTag} ${color}` : 태그를 템플릿 리터럴(``)을 사용해 태그 색상 형식으로 tag 배열에 저장했습니다. tag 배열은 카드 생성(POST) 요청에 request body에 포함되어 전송됩니다.
{tags.map((tag) => {
const [tagText, tagColor] = tag.split(' ');
return (
<Chip key={`${cardId}_tag_${tag}`} chipType="tag" color={tagColor}>
{tagText}
</Chip>
);
})}
- const [tagText, tagColor] = tag.split(' ') : 서버에서 받은 tag 데이터를 공백을 기준으로 text와 color로 구조 분해 할당 했습니다.
해결한 줄 알았지만, 이 방법도 문제가 있네요. 사용자가 태그를 입력할 때 공백을 추가해서 보내는 경우를 고려 못했습니다.
공백을 추가해서 입력하면 아래와 같이 나옵니다...
✨ 최종 해결 방법
사용자가 태그에 사용하지 않을 것 같은 특수 문자를 구분자로 사용하겠습니다.
태그 입력 시 구분자로 사용한 특수 문자를 포함 못하게 하는 것도 필수겠죠?
const handleTagInput = (e: React.ChangeEvent<HTMLInputElement>) => {
const newTag = e.target.value.trim();
const color = getTagColor();
const coloredTag = `${newTag}^${color}`;
if (!newTag || tags.includes(newTag) || newTag.includes('^')) return; // 빈 문자열 또는 중복 태그 방지
onAddTag(coloredTag);
e.target.value = '';
};
{tags.map((tag) => {
const [tagText, tagColor] = tag.split('^');
return (
<Chip key={`${cardId}_tag_${tag}`} chipType="tag" color={tagColor}>
{tagText}
</Chip>
);
})}
'프로젝트 > Next+TypeScript' 카테고리의 다른 글
[Taskify] 1차 배포 테스트(2) - 사용자 편의성 개선 (5) | 2024.12.26 |
---|---|
[Taskify] 1차 배포 테스트 - Trouble shooting (4) | 2024.12.24 |
[Taskify] 이미지 확장자 제한 추가 (5) | 2024.12.21 |
[Taskify] 할 일 카드 모달 컴포넌트 (feat. optimistic update) (6) | 2024.12.20 |
[Taskify] 무한스크롤 - 해결 (4) | 2024.12.19 |