๐ Tag ๋?
ํค์๋ ์ค์ฌ์ ๋ฒํผ๋ฒํผ ์๋๋๋ค์ด๋ผ๊ณ ๋ณผ ์ ์๋ค. (์ ํํ๋ ๋ฒํผ์ ์๋. "๋ฒํผ์ฒ๋ผ" ๋์ํ ๋ฟ)
์ผ๋ฐ์ ์ธ ๋ฒํผ๊ณผ์ ์ฐจ์ด๊ฐ ์๋ค๋ฉด, ํด๋ฆญํ์ ๋ ์๋ก์ด ์ด๋ฒคํธ๋ฅผ ์ฆ๊ฐ์ ์ผ๋ก ์คํํ์ง ์๋๋ค. ๋ฒํผ์ด ์๋๋๊น ๋น์ฐํ ์ด์ผ๊ธฐ ...
๋ค๋ง, ์ ํ๋ ํ๊ทธ๋ฅผ ๋ฐํ์ผ๋ก ์ ๋ณด๋ฅผ ์กฐํฉํด ์๋ก์ด ์ด๋ฒคํธ๊ฐ ๊ตฌ์ฑ๋๋ค.
ex. ํํฐ๋ ์คํธ์ ์ฒ์ ๋ค์ด๊ฐ์ ๋ ๊ด์ฌ์ฌ ํ๊ทธ๋ค์ ํด๋ฆญํ๋ฉด ๋ด ํผ๋๊ฐ ํ๊ทธ ๊ด๋ จ ์ด๋ฏธ์ง๋ค๋ก ์ฑ์์ง๋ค.
ex. ๋ ธ์ ์์ ๋ ธํธ๋ฅผ ์์ฑํ๋ฉฐ ๋ด๊ฐ ์ํ๋ ํ๊ทธ๋ค์ ๋ฌ์๋๋๋ค๋ฉด, ๋์ค์ ํด๋น ํ๊ทธ๊ฐ ์๋ ๋ ธํธ๋ค๋ง ์ทจํฉํด ๋ณผ ์ ์๋ค.
๐ Tag๋ฅผ ๊ตฌํํด๋ณด์.
โพ Tag ์ํ๋ง ์ถ์ ํ ๋
export const Tag = () => {
// dsfault ๊ฐ์ ๋ฃ์ด๋ ๋๊ณ ์ ๋ฃ์ด๋ ๋จ
const initialTags = [];
// ํ๊ทธ ๋ชฉ๋ก ์ํ ๊ด๋ฆฌ
const [tags, setTags] = useState(initialTags);
// ํ๊ทธ๋ฅผ ์ง์ ์ ๋ ์ํ ์
๋ฐ์ดํธ
const removeTags = (indexToRemove) => {
setTags(tags.filter((_, idx) => { return idx !== indexToRemove}));
};
// ํ๊ทธ๋ฅผ ์ถ๊ฐํ ๋ ์ํ ์
๋ฐ์ดํธ
const addTags = (event) => {
const text = event.target.value;
// ์ถ๊ฐํ๋ ค๋ ํ๊ทธ๊ฐ ๋น์ด์์ง ์๊ณ && ๊ธฐ์กด ํ๊ทธ ๋ชฉ๋ก์ ์ํ์ง ์์ ์๋ก์ด ํ๊ทธ์ผ๋๋ง ์ถ๊ฐ
if(text.length !== 0 && !tags.includes(text)){
setTags([...tags, text]);
event.target.value = '';
}
// ๋น ํ๊ทธ๊ฑฐ๋ ์ด๋ฏธ ์๋ ํ๊ทธ ์ผ๋ input box ๋ฅผ ๊น๋ํ ๋น์์คฌ๋ค
else{
event.target.value = '';
}
}
return (
<>
<TagsInput>
<ul id='tags'>
{tags.map((tag, index) => (
<li key={index} className='tag'>
<span className='tag-title'>{tag}</span>
<!--๊ฐ์๊ธฐ ๊ถ๊ธํ์ -> ์ด๋ฒคํธ ํจ๋ค๋ฌ๋ ์ ํด์ฃผ๋ ์ธ์๊ฐ์ด ์๋นํ ๋ค์ํ๋ค ?-->
<!--์ด๋ฒคํธ ๊ฐ์ฒด ๋ด์ index ํ๋กํผํฐ ๊ฐ์ด ๋ฐ๋ก ์๋๊ฑฐ๊ฒ ์ง ???!!!-->
<span className='tag-close-icon' onClick={() => {removeTags(index)}}>×</span>
</li>
))}
</ul>
<input
className='tag-input'
type='text'
// ํค ๊ฐ์ด Enter์ผ ๋๋ง ์ด๋ฒคํธ ๊ฐ์ฒด๋ฅผ ๋๊ฒจ์ฃผ๋๋ก ๊ตฌํ
onKeyUp={(e) => e.key === 'Enter' ? addTags(e) : null}
placeholder='Press enter to add tags'
/>
</TagsInput>
</>
);
};
โพ Tag ์ํ์ Input Value๋ฅผ ์ถ์ ํ ๋
export const Tag = () => {
// dsfault ๊ฐ์ ๋ฃ์ด๋ ๋๊ณ ์ ๋ฃ์ด๋ ๋จ
const initialTags = [];
// ํ๊ทธ ๋ชฉ๋ก ์ํ ๊ด๋ฆฌ
const [tags, setTags] = useState(initialTags);
// ์
๋ ฅ ๋ฌธ์ ์ํ ๊ด๋ฆฌ
const [text, setTexts] = useState('');
// ๋ฌธ์๊ฐ ์
๋ ฅ๋์์ ๋ ์ํ ์
๋ฐ์ดํธ
const addTexts = (event) => {
setTexts(event.target.value);
}
// ํ๊ทธ๋ฅผ ์ง์ ์ ๋ ์ํ ์
๋ฐ์ดํธ
const removeTags = (indexToRemove) => {
setTags(tags.filter((_, idx) => { return idx !== indexToRemove}));
};
// ํ๊ทธ๋ฅผ ์ถ๊ฐํ ๋ ์ํ ์
๋ฐ์ดํธ
const addTags = () => {
// ์ถ๊ฐํ๋ ค๋ ํ๊ทธ๊ฐ ๋น์ด์์ง ์๊ณ && ๊ธฐ์กด ํ๊ทธ ๋ชฉ๋ก์ ์ํ์ง ์์ ์๋ก์ด ํ๊ทธ์ผ๋๋ง ์ถ๊ฐ
if(text.length !== 0 && !tags.includes(text)){
setTags([...tags, text]);
setText('');
}
// ๋น ํ๊ทธ๊ฑฐ๋ ์ด๋ฏธ ์๋ ํ๊ทธ ์ผ๋ input box ๋ฅผ ๊น๋ํ ๋น์์คฌ๋ค
else{
setText('');
}
}
return (
<>
<TagsInput>
<ul id='tags'>
{tags.map((tag, index) => (
<li key={index} className='tag'>
<span className='tag-title'>{tag}</span>
<span className='tag-close-icon' onClick={() => {removeTags(index)}}>×</span>
</li>
))}
</ul>
<input
className='tag-input'
type='text'
value={text}
onChange={addTexts}
// ํค ๊ฐ์ด Enter์ผ ๋๋ง ์ด๋ฒคํธ ๊ฐ์ฒด๋ฅผ ๋๊ฒจ์ฃผ๋๋ก ๊ตฌํ
onKeyUp={(e) => e.key === 'Enter' ? addTags : null}
placeholder='Press enter to add tags'
/>
</TagsInput>
</>
);
};
ํ์ฌ ๊ตฌํํ ์ํ๋ ์ ๋ ฅ์ฐฝ์ด ํ๋๋ผ input ๊ฐ์ ์ํ๋ฅผ ๋ฐ๋ก ๊ด๋ฆฌํ๋ ๊ฒ ๋นํจ์จ์ ์ด์๋ค.
๊ทธ๋๋ useState๋ฅผ ์ด๋ป๊ฒ ์จ์ผํ๋ ์ง ๊ฐ์ ์ก์ ์ ์์ด ์ข์๋ค. :)
๐ ์ด๊ฑด ์ ํ ์คํธ๋ฅผ ํต๊ณผํ๊ณ , ์ ๊ฑด ์ ํต๊ณผํ์ง ๋ชปํ๋๊ฐ ????
โ ์ฝ๋ ์๊ตฌ ์ฌํญ : '์ค๋ณต๋ ๊ฐ์ด ์ด๋ฏธ ์กด์ฌํ๋ ๊ฒฝ์ฐ, Enter๋ฅผ ๋๋ฌ๋ ํ๊ทธ๊ฐ ์ถ๊ฐ๋์ง ์์์ผ ํฉ๋๋ค.'
โ ๋ ๊ฒฝ์ฐ ๋ชจ๋ Enter key๊ฐ ํด๋ฆญ๋์์ ๋น์์ input value๋ฅผ console๋ก ์ฐ์ด๋ณด์๋ค.
๐ ์ฒซ๋ฒ์งธ ๊ฒฝ์ฐ -> ์ ๋ ฅ๊ฐ์ด ๊ฐ์ ํ๊ทธ๋ฅผ ์ ๋ ฅํ์ ๋ input value๋ฅผ ์ญ์ ํ์ง ์๋๋ค. -> ํ ์คํธ ํต๊ณผ
๐ก ๋๋ฒ์งธ ๊ฒฝ์ฐ -> ์ ๋ ฅ๊ฐ์ด ๊ฐ์ ํ๊ทธ๋ฅผ ์ ๋ ฅํ์ ๋ input value๋ฅผ ์ญ์ ํ๋ค. -> ํ ์คํธ ๋ฏธํต๊ณผ
๋ ๋ค ํ๊ทธ๊ฐ ์ถ๊ฐ๋์ง ์๋ ์ ์ ๋์ผํ๋ค.
๋ค๋ง input box์ ์ํ๊ฐ ๋ค๋ฅผ ๋ฟ์ธ๋ฐ .... ๋ ๊น๋ํ๊ฒ ํ๋ค๊ณ input value๋ฅผ ์์ธ์ฒ๋ฆฌ๋ก ๋น์์คฌ๋๋ฐ ....
์ด ํ ์คํธ ์ผ์ด์ค๊ฐ ์ํ๋ ๊ฑด ๋ญ์์๊น ???? ์๊ตฌ ์ฌํญ์ ์ถฉ๋ถํ ๊ตฌํํ๋ค๊ณ ์๊ฐํ๋๋ฐ ํต๊ณผ๊ฐ ์๋๋๊น ๋๋ฌด ์์ํ๋ค.
์ด๋๋ถํฐ์๋์ ์ ๊ฐ ํ
์คํธ์ผ์ด์ค ๋ฌธ๋ฒ์ ํ๊ธฐ ์์ํ ๊ฒ ...
โ ํ ์คํธ ์ผ์ด์ค๋ฅผ ์ดํด๋ณด์.
it('Enterํค๋ฅผ ๋๋ฅด๋ฉด ์ค์ ํ๊ทธ๊ฐ ์ถ๊ฐ๋์ด์ผ ํฉ๋๋ค.', async () => {
const { queryAllByRole, container } = render(<Tag />);
const input = container.querySelector('input');
expect(input).toBeTruthy();
userEvent.type(input, 'kimcoding');
fireEvent.keyUp(input, { key: 'Enter', code: 'Enter' });
await waitFor(() => {
expect(queryAllByRole('listitem').length).toBeGreaterThan(1);
});
await waitFor(() => {
const tagLength = queryAllByRole('listitem').length;
expect(
queryAllByRole('listitem')[tagLength - 1].textContent.slice(0, 9)
).toBe(input.value);
});
});
โ queryAllByRole ์ ์ด๋ค ์ญํ ์ธ๊ฐ
querySelector ์ ๊ฐ์ DOM API ๊ฐ ์๋์๋ค !! (์ถฉ๊ฒฉ)
์ฐพ์๋ณด๋ ํ ์คํธ ์ผ์ด์ค ์์ฑ์ ์ํ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๊ฐ ๋ฐ๋ก ์๋๋ผ. ๊ทธ ์ค์ ์ํ ํ๋์ ํจ์์๋ค.
โ ๊ทธ๋ผ Role์ ๋ฌด์์ธ๊ฐ
getElementById ๋ HTML ํ๊ทธ์ id๊ฐ์ ๊ธฐ์ค์ผ๋ก element๋ฅผ ๊ฐ์ ธ์ค๊ณ ,
getElementByClassName ์ HTML ํ๊ทธ์ class ์ด๋ฆ์ ๊ธฐ์ค์ผ๋ก element๋ฅผ ๊ฐ์ ธ์จ๋ค.
๋ญ๊ฐ Role๋ ๋น์ทํ๊ฒ HTML ์ดํธ๋ฆฌ๋ทฐํธ์ธ๊ฐ ? ํด์ ์ฐพ์๋ดค์ง๋ง ๋์ค์ง ์์๋ค.
์๊ณ ๋ณด๋ Role์ ์๊ฐ๋ณด๋ค ์์ฃผ ์์ฃผ ๋๊ณ ํฌ๊ด์ ์ธ ๊ฐ๋ ์ ๊ฐ์ง ์์ด์๋ค.
๋ด๊ฐ ์๊ณ ์๋ "HTML ์ดํธ๋ฆฌ๋ทฐํธ"๋ค์ ํฌ์ฉํ๊ณ ์์๋ค !ใ !
โ listitem์ li ์์ฑ์ ๋ชจ์์ด์๋ค
role์ด๋ผ๋๊ฒ attribute๋์ ๋ ๋ค๋ฅด๊ฒ ... ํ ์คํธ ์ผ์ด์ค์๋ง ์ฐ์ด๋ ๊ฑด๊ฐ ?? ์ถ๊ณ . ์ผ๋จ ๋ ์์๋ด์ผ๊ฒ ๋ค.
li ํ๊ทธ๋ก ๊ฒ์ํ๊ณ , ํด๋น ๋ฐฐ์ด์ ๋ง์ง๋ง ์ธ๋ฑ์ค๋ฅผ ๊ฒ์ํ์ ๋ ํ ์คํธ์ผ์ด์ค์ ๋ง๋ ๊ฒฐ๊ณผ๊ฐ ์ถ๋ ฅ๋์๋ค.
โ input์ value๊ฐ์ด ๋น๊ต ๊ธฐ์ค์ด์๊ธฐ ๋๋ฌธ์ ๋ด ๋ก์ง์ ํต๊ณผํ ์ ์์๋ค.
listitem์ด ๊ฐ์ง ๋ฐฐ์ด์ ๋ง์ง๋ง ์ธ๋ฑ์ค ๊ฐ์ textContent์ ๋ฌธ์์ด ๋ณต์ฌ๋ณธ์ 'kimcoding'์ด์๋ค.
์ฒซ๋ฒ์งธ ๊ฒฝ์ฐ์ input value๋ 'kimcoding'์ด์๊ณ , ๋๋ฒ์งธ ๊ฒฝ์ฐ์ input value๋ ' '์ด์๋ค.
์ ๋ ฅ๊ฐ์ด ๊ธฐ์กด ํ๊ทธ์ ์ค๋ณต๋์์ ๋ ํ๊ทธ๋ฅผ ์ถ๊ฐํ์ง ์๋ ๋ก์ง์ ์งฐ์ง๋ง ์์ธ์ ๋ณ์์ ๊ฑธ๋ ธ๋ค ใ ใ ใ
๐ ๋๋์
โ ํ ์คํธ์ผ์ด์ค์ ์ด๋ฆ์ด ๋ฐ๋์ด์ผํ ๊ฒ๊ฐ๋ค. --> ํน์ ํ ์คํธ ์ผ์ด์ค๋ฅผ ๊ณต๋ถ์ํค๊ธฐ ์ํ ํฐ๊ทธ๋ฆผ์ด์๋ ..?
โ UX์ ๋ํด ๋ค์ ์๊ฐํด๋ณผ ์ ์์๋ค. --> ์ฌ์ฉ์ ์ ์ฅ์์ ํ๊ทธ๊ฐ ์ค๋ณต๋์๋ค๋ ๊ฑธ ์ด๋ป๊ฒ ์ธ์ง์ํค๋ ๊ฒ ์ข์๊น ?
์ด์ฉ๋ฉด input ์ฐฝ์ด ๋น์์ง์ง ์๊ฒ ํ๋ ๋ฐฉ๋ฒ์ด ๋ ํจ์จ์ ์ด๋ ์๊ฐ๋ ๋ค์๋ค. ๋์ฒ๋ผ input ์ฐฝ์ด ๋น์์ง๋ฉด ์ ๋ด๊ฐ ์ ๋ ฅ ์์ฒด๋ฅผ ์ํ์๋ ? ํ๋ฉด์ ๋ค์ ์ ๋ ฅํด๋ณด๋ side effect๋ฅผ ๋ถ๋ฌ์ฌ ์๋ ์๊ณ ใ ใ "ํ๊ทธ ๊ฐ์ด ์ค๋ณต๋์์ต๋๋ค" ๋ผ๋ ๋ฌธ๊ตฌ๋ฅผ ๋์ฐ๊ณ ์ฌ๋ผ์ง๊ฒ ํ๋ ๊ฒ๋ ๊ด์ฐฎ์ ๋ฐฉ๋ฒ๊ฐ๊ณ , input์ฐฝ ์์ฒด๋ฅผ ํ๋ค๋ฉฐ ๊ฐ์ ๊ฑฐ๋ถํ๋ ๋ชจ์ ๋ ์ฌ๋ฐ์ ๊ฒ ๊ฐ๋ค ใ ใ ใ *(๋จธ์ฑ)
๐ Tag ๊ตฌํ ๊ฒฐ๊ณผ
'Front-end > React' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
REACT ์ปดํฌ๋ํธ ์๋ช ์ฃผ๊ธฐ Component Life Cycle (0) | 2021.10.01 |
---|---|
ํญ๊ณตํธ ๊ฒ์์ฐฝ ๋ง๋ค๋ฉด์ useEffect ๊ณต๋ถํ๊ธฐ (0) | 2021.09.07 |
React To Do List ๋ง๋ค๋ฉด์ useState, useRef ๊ณต๋ถํ๊ธฐ (0) | 2021.08.26 |
React ์ข์์ ๋ฒํผ ๋ง๋ค๋ฉด์ state ๊ณต๋ถ (0) | 2021.08.25 |
React ์์ (0) | 2021.08.19 |
๋๊ธ