이전 포스팅에 보여드렸던 모달창입니다. 여기서 태그를 입력하는 필드가 있습니다. 이를 velog에 있는 태그 입력하는 것과 비슷하게 만들어보겠습니다.
우선 모달창 안에 있는 form에 대한 컴포넌트입니다. 본문 내용과 관련 없는 부분들은 생략 및 삭제하였습니다.
import styled from 'styled-components';
import React from 'react';
import TagsComponent from './Tag';
export default function CreateRoomForm({
inputs,
onChange,
onKeyPress,
onDeleteTag,
}) {
const { newTag, tags } = inputs;
return (
<Form onSubmit={mutate}>
...
<Section>
<TagsComponent
newTag={newTag}
tags={tags}
onChange={onChange}
onKeyPress={onKeyPress}
onDeleteTag={onDeleteTag}
/>
</Section>
...
</Form>
);
}
const Form = styled.form`
display: flex;
flex-direction: column;
align-items: flex-start;
justify-content: flex-start;
width: 100%;
color: #b0b8c1;
font-size: 1.4rem;
font-family: IBMPlexSansKRRegular, Arial;
overflow-y: auto;
::-webkit-scrollbar {
display: none;
}
`;
const Section = styled.div`
display: flex;
flex-direction: column;
align-items: center;
margin-top: 2.9rem;
width: 100%;
`;
import styled from 'styled-components';
import { ReactComponent as DeleteTag } from '../../../assets/svg/deleteTag.svg';
export default function TagsComponent({
newTag,
tags,
onChange,
onKeyPress,
onDeleteTag,
}) {
return (
<>
<Label htmlFor="tag">태그</Label>
<TagComponent>
{tags.map((myTag, index) => (
<Tag
onClick={(e) => onDeleteTag(e, index)}
key={myTag.concat(`${index}`)}
>
<TagName key={myTag}>#{myTag}</TagName>
<TagButton type="button">
<DeleteTag />
</TagButton>
</Tag>
))}
<Input
id="tag"
name="newTag"
type="text"
value={newTag}
onChange={onChange}
onKeyPress={onKeyPress}
placeholder="태그를 입력하세요."
/>
</TagComponent>
</>
);
}
const Label = styled.label`
width: 100%;
line-height: 2.9rem;
`;
const TagComponent = styled.div`
display: flex;
align-items: center;
border-radius: 0.6rem;
width: 100%;
flex-wrap: wrap;
gap: 1.2rem;
`;
const Input = styled.input`
height: 4.9rem;
min-width: 15rem;
max-width: 15rem;
background: transparent;
outline: none;
color: #f9fafb;
font-size: 1.5rem;
background-color: #191f28;
border-radius: 0.6rem;
padding: 0 1.6rem;
`;
const Tag = styled.div`
display: flex;
align-items: center;
border-radius: 0.6rem;
background-color: rgba(69, 178, 107, 0.1);
padding: 0.5rem 1rem;
cursor: pointer;
&:hover {
background-color: rgba(69, 178, 107, 0.2);
}
`;
const TagButton = styled.button`
cursor: pointer;
margin-left: 1rem;
display: flex;
flex-direction: column;
align-items: center;
`;
const TagName = styled.div`
color: rgba(69, 178, 107, 1);
font-family: IBMPlexSansKRRegular, Arial;
`;
Tag
는 태그가 추가되는 곳이고 Input
은 태그를 입력할수 있는 입력창입니다. 이 둘을 감싸고 있는 TagComponent
는 flex
로 설정하였고 태그를 많이 추가하여 길어질때 여러 줄로 생기게 하기 위해 flex-wrap
속성을 wrap
으로 해주었습니다.
각 Tag
에 onClick
이벤트를 추가하여 클릭할 때 해당 태그가 삭제되게 하였습니다. Input
에 onKeyPress
속성으로 사용자가 스페이스바나 엔터키를 누를경우 해당 input
값을 tags
배열에 추가하였습니다.
const onKeyPress = (e: React.KeyboardEvent<HTMLElement>) => {
if (e.key === 'Enter' || e.key === ' ') {
e.preventDefault();
if (tags.includes(newTag)) {
toast.error('이미 추가된 태그입니다.');
setInputs((prev) => {
return {
...prev,
newTag: '',
};
});
return;
}
if (newTag !== '') {
onAddTag();
}
}
};
코드로 좀 더 자세히 살펴봅시다.
e.preventDefault()
를 작성한 이유는 이벤트 버블링으로 인해 발생되는 폼 제출을 막기위함 입니다. newTag
(사용자가 input창에 입력한 값)를 ''로 초기화해줍니다. newTag
가 빈 스트링인지 확인 후 아닐 경우 tags
배열에 추가해줍니다.toast라이브러리는 공식 사이트를 참고하시면 좋을 것 같습니다.
원래는 방 이름을 입력하는 칸처럼 input을 설정하고 그 아래에 사용자가 추가하는 태그들을 보여주었는데 이렇게 바꾼게 더 이쁜것 같네요ㅎㅎ