[๐Ÿ’ป ์ฝ”๋“œ์Šคํ…Œ์ด์ธ  FE 44๊ธฐ]pre-project - 9์ผ์ฐจ

JiEunยท2023๋…„ 6์›” 21์ผ
0

โœ”๏ธ ์‹œ์ž‘

์„œ๋ฒ„์™€์˜ ํ†ต์‹ ์— ์„ฑ๊ณตํ•˜๊ณ  ๊ธฐ๋Šฅ ๊ฐœ๋ฐœ์— ๋“ค์–ด๊ฐ”๋‹ค.

๋‚˜๋Š” ์งˆ๋ฌธ ์ž‘์„ฑํŽ˜์ด์ง€์—์„œ ํƒœ๊ทธ ์„ ํƒ ์˜์—ญ์„ ๋งก์•˜๋‹ค.


๐Ÿ“ ํƒœ๊ทธ ์„ ํƒ

์š”๊ตฌ ์‚ฌํ•ญ์€

  • 3๊ฐœ ๊นŒ์ง€ ์„ ํƒ์ด ๊ฐ€๋Šฅํ•˜๋‹ค.
  • ๋ฐฐ์—ด ํ˜•์‹์œผ๋กœ ๋“ค์–ด๊ฐ„๋‹ค.

์ด์ •๋„ ์˜€๋˜ ๊ฑฐ ๊ฐ™๋‹ค.

์šฐ์„  API ๋ช…์„ธ์„œ์—์„œ ํƒœ๊ทธ ๋ฆฌ์ŠคํŠธ ๊ด€๋ จํ•ด ์ž‘์—…์ด ๋˜์–ด์žˆ์ง€ ์•Š์•„ ๋”๋ฏธ ๋ฐ์ดํ„ฐ๋ฅผ ๋งŒ๋“ค์–ด ์ง„ํ–‰ํ–ˆ๋‹ค.

export const tagList =
    [
      {
        tagName: 'java',
        tagDescription: 'Java programming language'
      }, {
        tagName: 'spring-boot',
        tagDescription: 'Spring Boot framework'
      }, {
        tagName: 'python',
        tagDescription: 'Python programming language'
      },
      .
      .
      .
     ]

๋”๋ฏธ ๋ฐ์ดํ„ฐ๋ฅผ ๋งŒ๋“ค๊ณ 

{
  tagList.map((el) => (
    <TagCheckBoxed key={el.tagName}>
      <TagCheck
        type="checkbox"
        id={el.tagName}
        value={el.tagName}
        />
      <TagLabel htmlFor={el.tagName}>
        <span>{el.tagName}</span>
      </TagLabel>
    </TagCheckBoxed>
  ))
}

map๋ฉ”์„œ๋“œ๋ฅผ ์ด์šฉํ•ด ํ™”๋ฉด์— ๋ณด์—ฌ์ฃผ์—ˆ๋‹ค.

map๋ฉ”์„œ๋“œ๋ฅผ ์‚ฌ์šฉํ•  ๋•Œ ๊ณ ์œ ํ•œ key๊ฐ’์ด ๋“ค์–ด๊ฐ€์•ผ ํ•˜๋Š”๋ฐ id๊ฐ’์€ ์—†๊ณ ,
index๋Š” ์ถ”ํ›„ ์˜ค๋ฅ˜๊ฐ€ ๋‚  ์ˆ˜ ์žˆ๊ธฐ์— tagName์œผ๋กœ ์ง€์ •ํ•ด ์คฌ๋‹ค.

const [tags, setTags] = useState([]);

const handlerTag = (name, description) => {
    const tagSelected = tags.some((el) => el.tagName === name);

    if (tagSelected) {
      const updatedTags = tags.filter((el) => el.tagName !== name);
      setTags(updatedTags);
    } else {
      const newTag = { tagName: name, tagDescription: description };
      setTags((prevTags) => [...prevTags, newTag]);
    }
  };
.
.
.
{
  tagList.map((el) => (
    <TagCheckBoxed key={el.tagName}>
      <TagCheck
        type="checkbox"
        id={el.tagName}
        value={el.tagName}
        onChange={() => handlerTag(el.tagName, el.tagDescription)}
        ></TagCheck>
      <TagLabel htmlFor={el.tagName}>
        <span>{el.tagName}</span>
      </TagLabel>
    </TagCheckBoxed>
  ))
}
  • useState๋ฅผ ์ด์šฉํ•ด tags ์ƒํƒœ๋ฅผ ๋งŒ๋“ค์—ˆ๋‹ค.
    ๋งŒ๋“ค์–ด tag name, description๋ฅผ ์ธ์ž๋กœ ๋ฐ›์•„ ์ „๋‹ฌํ•  ์ˆ˜ ์žˆ๋„๋ก ํ–ˆ๋‹ค.

  • const tagSelected = tags.some((el) => el.tagName === name);
    some๋ฉ”์„œ๋“œ๋Š” ํ•ด๋‹น ๊ฐ’์— ๋”ฐ๋ผ boolean ๊ฐ’์„ ๋ฐ˜ํ™˜ํ•œ๋‹ค.

  • tags ์š”์†Œ์˜ tagName๊ณผ ์ธ์ž๋กœ ๋“ค์–ด์˜จ name์ด ๋™์ผํ•˜๋ฉด true, ์•„๋‹ˆ๋ฉด false๋กœ ๋ฐ˜ํ™˜ํ•œ ๊ฐ’์„
    tagSelected์— ํ• ๋‹นํ•ด ์ฃผ์—ˆ๋‹ค.

  • ์ดํ›„ ์กฐ๊ฑด๋ฌธ์œผ๋กœ tagSelected๊ฐ€ true์ธ ๊ฒฝ์šฐ
    const updatedTags = tags.filter((el) => el.tagName !== name);
    tagName์ด ๋™์ผํ•œ ๊ฐ’๋งŒ ๋บ€ ๋‚˜๋จธ์ง€๋ฅผ setTags(updatedTags) tags์— ์ถ”๊ฐ€ํ–ˆ๋‹ค.

  • ์•„๋‹Œ ๊ฒฝ์šฐ const newTag = { tagName: name, tagDescription: description };
    setTags((prevTags) => [...prevTags, newTag]); ๊ธฐ์กด์— ์žˆ๋˜ ๊ฐ’์„ ๊ทธ๋Œ€๋กœ ๋‘๊ณ  ์ƒˆ๋กœ์šด ๊ฐ’ newTag๋ฅผ ์ถ”๊ฐ€ํ•ด ์คฌ๋‹ค.

3๊ฐœ๋งŒ ์ฒดํฌ ๋˜๋„๋ก ์ž‘์—…ํ•˜๊ธฐ

3๊ฐœ๋งŒ ์ฒดํฌ ๋˜๋„๋ก checkCount๋ผ๋Š” ์ƒํƒœ๋ฅผ ํ•˜๋‚˜ ๋” ๋งŒ๋“ค์–ด ์คฌ๋‹ค.

const [tags, setTags] = useState([]);
const [checkCount, setCheckCount] = useState(0);

const handlerTag = (name, description) => {
  const tagSelected = tags.some((el) => el.tagName === name);

  if (tagSelected) {
    const updatedTags = tags.filter((el) => el.tagName !== name);
    setTags(updatedTags);
    setCheckCount((prevCount) => prevCount - 1);
  } else {
    const newTag = { tagName: name, tagDescription: description };
    setTags((prevTags) => [...prevTags, newTag]);
    setCheckCount((prevCount) => prevCount + 1);
  }
};

๊ธฐ์กด์— ์ž‘์„ฑํ•œ ์ฝ”๋“œ์— ๋„ฃ์–ด์คฌ๋‹ค.
tagSelected๊ฐ€ true์ผ ๋•Œ๋Š” -1๋ฅผ ์•„๋‹Œ ๊ฒฝ์šฐ +1์„ ํ•ด์คฌ๋‹ค.

checkCount๊ฐ€ 3์ด ๋˜๋ฉด ํด๋ฆญ์ด ๋˜์ง€ ์•Š๋„๋ก input checkbox๋ฅผ ์ˆ˜์ •ํ•ด ์คฌ๋‹ค.

{
  tagList.map((el) => (
    <TagCheckBoxed key={el.tagName}>
      <TagCheck
        type="checkbox"
        id={el.tagName}
        value={el.tagName}
        checked={tags.some(item => item.tagName === el.tagName)}
        disabled={!tags.some(item => item.tagName === el.tagName) && checkCount >= 3}
        onChange={() => handlerTag(el.tagName, el.tagDescription)}
        ></TagCheck>
      <TagLabel htmlFor={el.tagName}>
        <span>{el.tagName}</span>
      </TagLabel>
    </TagCheckBoxed>
  ))
}

disabled์˜ ์กฐ๊ฑด์„
!tags.some(item => item.tagName === el.tagName) && checkCount >= 3 ์คฌ๋‹ค.

ํ•ด๋‹น ์กฐ๊ฑด์ด ๋งŒ์กฑํ•˜๋ฉด false๋กœ ์ฒดํฌ๋˜์ง€ ์•Š๋„๋ก ํ–ˆ๋‹ค.

๐Ÿ“๋ง‰ํ˜”๋˜ ๋ถ€๋ถ„

input์˜ checked์˜ ์ƒํƒœ์— ๋”ฐ๋ผ ํ‘œ์‹œํ•ด ์ฃผ๊ณ  ์‹ถ์—ˆ๋‹ค.
์ฒ˜์Œ์—๋Š” ์ƒํƒœ๋ฅผ ํ•˜๋‚˜ ๋งŒ๋“ค์–ด ๋„ฃ์—ˆ์ง€๋งŒ ์—๋Ÿฌ๊ฐ€ ๋‚ฌ๋‹ค.

๊ทธ๋Ÿฌ๋‹ค some๋ฉ”์„œ๋“œ๋„ boolean์œผ๋กœ ๋ฐ˜ํ™˜ํ•˜๋‹ˆ ๊ตณ์ด ์ƒํƒœ๋ฅผ ๋งŒ๋“ค ํ•„์š”๊ฐ€ ์—†๋‹ค ์ƒ๊ฐํ–ˆ๋‹ค.
๋‹คํ–‰ํžˆ ์ž˜ ์ง„ํ–‰ ๋˜๋Š”๊ฑฐ ๊ฐ™์•˜๋‹ค.

disabled๋„ event.target.checked๋ฅผ ์ด์šฉํ•ด ์ง„ํ–‰ํ•˜๋ ค๊ณ  ํ–ˆ์œผ๋‚˜
์ƒ๊ฐ๋Œ€๋กœ ์ž˜ ๋˜์ง€ ์•Š์•˜๋‹ค ๊ทธ๋Ÿฌ๋‹ค input์˜ disabled๋ฅผ ์•Œ๊ฒŒ ๋˜์–ด ํ•ด๊ฒฐํ•  ์ˆ˜ ์žˆ์—ˆ๋‹ค.


โœ”๏ธ Keep

  • ์ž‘์—… ์ค‘ ํ•ด๊ฒฐ์ด ์ž˜ ๋˜์ง€ ์•Š๋Š” ๋ถ€๋ถ„์ด ์žˆ์„ ๊ฒฝ์šฐ ๋‹ค๋ฅธ ๋ฐฉํ–ฅ์œผ๋กœ ํ•ด๊ฒฐํ–ˆ๋‹ค.
  • ์—ฌ๋Ÿฌ ๋ฉ”์„œ๋“œ๋ฅผ ์‚ฌ์šฉํ•ด ๋ณด๋ ค๊ณ  ํ–ˆ๋‹ค.
  • ์ตœ๋Œ€ํ•œ input ์†์„ฑ์„ ํ™œ์šฉํ•˜๋ ค๊ณ  ํ–ˆ๋‹ค.

โœ๏ธ Problem

  • ์ž‘์„ฑ ํŽ˜์ด์ง€๋Š” ๊ฐ๊ฐ ํŒŒํŠธ๋ฅผ ๋งก์•„ ์ถ”ํ•ฉํ•œ ํ˜•์‹์œผ๋กœ ์ง„ํ–‰ํ–ˆ๋‹ค. ์ฝ”๋“œ ๋ฆฌ๋ทฐ๋ฅผ ์ง„ํ–‰ ํ›„ ๋จธ์ง€๋ฅผ ํ•  ์ค„ ์•Œ์•˜์ง€๋งŒ ๊ทธ๋ƒฅ ๋จธ์ง€ ํ›„ ์ถ”ํ•ฉํ–ˆ๋‹ค.
  • ์ถ”ํ•ฉํ•˜๋Š” ๊ณผ์ •์—์„œ ๋‹ค๋ฅธ ๋ถ„์ด ๋‚˜์˜ ์ฝ”๋“œ์˜ ๋„ค์ด๋ฐ ๋“ฑ์„ ์ˆ˜์ •ํ•˜์‹  ํ”์ ์„ ๋ฐœ๊ฒฌํ–ˆ๋‹ค.
    - ์ฐจ๋ผ๋ฆฌ ๋‚˜ํ•œํ…Œ ๋ง์„ํ•˜๊ณ  ์ˆ˜์ •ํ•ด ์˜๊ฒฌ์„ ์ œ์‹œ ํ•˜์…จ์œผ๋ฉด ์–ด๋• ์„๊นŒ ์‹ถ์—ˆ๋‹ค.
    ๊ทธ๋ž˜์•ผ ๋‚ด๊ฐ€ ์–ด๋Š ๋ถ€๋ถ„์ด ๋ถ€์กฑํ•œ์ง€ ํŒŒ์•…ํ•˜๊ณ  ๋˜‘๊ฐ™์€ ์‹ค์ˆ˜๋ฅผ ์ €์ง€๋ฅด์ง€ ์•Š๋„๋ก ์ฃผ์˜ํ–ˆ์„ ๊ฑฐ๋‹ค.

๐Ÿš€ Try

  • github์— PR์„ ๋‚ ๋ฆฌ๋ฉด ๊ผญ ์ฝ”๋“œ ๋ฆฌ๋ทฐ ํ›„ ๋จธ์ง€๋ฅผ ํ•ด์•ผํ•  ๊ฒƒ ๊ฐ™๋‹ค.
    - ์ฝ”๋“œ ๋ฆฌ๋ทฐ๊ฐ€ ์ง„์งœ ์ค‘์š”ํ•˜๋‹ค ์ƒ๊ฐํ•œ๋‹ค.
    - ๊ทผ๋ฐ ํ”„๋กœ์ ํŠธ ๊ธฐ๊ฐ„์— ์ซ’๊ธฐ๋‹ค ๋ณด๋ฉด ์–ด์ฉ” ์ˆ˜ ์—†์ด ๋„˜์–ด๊ฐ€๋Š” ์ƒํ™ฉ์ด ๋ฐœ์ƒํ•˜๊ฒŒ ๋˜๋Š” ๊ฒƒ ๊ฐ™๋‹ค.
  • ์ดํ›„์—๋„ ๋™์ผํ•œ ์ผ์ด ๋ฐœ์ƒํ•œ๋‹ค๋ฉด ์ฝ”๋“œ ๋ฆฌ๋ทฐ ์š”์ฒญ์„ ํ•˜์ž๊ณ  ๊ฑด์˜ํ•ด ๋ด์•ผ๊ฒ ๋‹ค.

โœ๏ธ ๋งˆ์น˜๋ฉฐ

๋“œ๋””์–ด ๊ธฐ๋Šฅ ๊ฐœ๋ฐœ์— ๋“ค์—ˆ๊ฐ”๋‹ค.
๋งˆํฌ์—… ๋‹จ๊ณ„์—์„œ๋Š” tailwind CSS๊ฐ€ ์ต์ˆ™ํ•˜์ง€ ์•Š์•„ ์˜ค๋ž˜ ๊ฑธ๋ ธ์ง€๋งŒ
๊ธฐ๋Šฅ์ ์ธ ๋ถ€๋ถ„์€ ์ƒ๊ฐ ๋ณด๋‹ค ๋นจ๋ฆฌ ๋๋‚  ์ˆ˜ ์žˆ์—ˆ๋‹ค.

ํ”„๋กœ์ ํŠธ ์ž‘์—… ๊ธฐ๊ฐ„์ด ์งง์•„ ์ฝ”๋“œ ๋ฆฌ๋ทฐ ์—†์ด ๋ฐ”๋กœ ๋จธ์ง€๋ฅผ ํ•œ ์ ์€ ์•„์‰ฝ๋‹ค๊ณ  ์ƒ๊ฐํ•œ๋‹ค.
์ฝ”๋“œ ๋ฆฌ๋ทฐ๋ฅผ ํ†ตํ•ด ๋‚˜์˜ ์ฝ”๋“œ์— ๋Œ€ํ•œ ์ƒ๋Œ€๋ฐฉ์˜ ์ƒ๊ฐ์„ ์•Œ ์ˆ˜ ์žˆ๊ณ  ์ข€ ๋” ๊ฐœ์„ ํ•  ์ˆ˜ ์žˆ๋‹ค ์ƒ๊ฐํ•˜๋Š”๋ฐ
๊ทธ ์ ์ด ์‚ฌ๋ผ์ง€๋‹ˆ ๊ทธ ๋งŒํผ ๋‚˜์˜ ์„ฑ์žฅ ๊ธฐํšŒ๋„ ์—†์–ด์ง„๋‹ค๊ณ  ์ƒ๊ฐํ•œ๋‹ค.

profile
๐Ÿ’ป ํ”„๋ก ํŠธ์—”๋“œ๋ฅผ ๋ชฉํ‘œ๋กœ ์„ฑ์žฅ ์ค‘! (์•Œ์•„๋ดค๋˜ ๋‚ด์šฉ ๋“ฑ์„ ์ •๋ฆฌํ•˜๊ธฐ)

0๊ฐœ์˜ ๋Œ“๊ธ€