๋ณธ๋ฌธ ๋ฐ”๋กœ๊ฐ€๊ธฐ

Frontend Dev/๐Ÿฅ ์ฝ”๋“œ์Šคํ…Œ์ด์ธ  FE ๋ถ€ํŠธ์บ ํ”„

Section3 Unit3 [React] Custom Component - ๊ณผ์ œ React Custom Component (Advanced Challenge)

๋ฐ˜์‘ํ˜•


Section3 Unit3 [React] Custom Component
- ๊ณผ์ œ React Custom Component (Advanced Challenge)

 

โญ๏ธ ๊ณผ์ œ. React Custom Component

์ง€๋‚œ Bare Minimum ๊ตฌํ˜„์— ์ด์–ด ์ด๋ฒˆ์—๋Š” Advanced ๊ตฌํ˜„์„ ์™„๋ฃŒํ–ˆ๋‹ค. 

 

Section3 Unit3 [React] Custom Component - ๊ณผ์ œ React Custom Component (Bare Minimum)

Section3 Unit3 [React] Custom Component - ๊ณผ์ œ React Custom Component (Bare Minimum) โญ๏ธ ๊ณผ์ œ. React Custom Component ๐Ÿ”ฅ ํ•™์Šต๋ชฉํ‘œ React, Styled-Component, Storybook์„ ํ™œ์šฉํ•ด UI ์ปดํฌ๋„ŒํŠธ ๊ฐœ๋ฐœ • Styled Components๋ฅผ ํ™œ์šฉํ•ด ๋‹ค์–‘

fay-story.com

 

๐Ÿท๏ธ Advanced Challenge: Autocomplete, ClickToEdit

 

โœ๏ธ ๊ตฌํ˜„ ๊ณผ์ • & ์ฝ”๋“œ 

→ ๋ชฐ๋ž๊ฑฐ๋‚˜ ํ—ท๊ฐˆ๋ ธ๋˜ ๋ถ€๋ถ„ ์œ„์ฃผ๋กœ โœจ๋ฉ”๋ชจ

 

5. Autocomplete

ํ…์ŠคํŠธ input์— ๊ฐ’์„ ์ž…๋ ฅํ•˜๋ฉด, dropdown์œผ๋กœ input ๊ฐ’๊ณผ ์œ ์‚ฌํ•œ ์ถ”์ฒœ ๊ฒ€์ƒ‰ ์˜ต์…˜์„ ๋ณด์—ฌ์ฃผ๋Š” ์ž๋™ ์™„์„ฑ ๊ธฐ๋Šฅ์œผ๋กœ ์‚ฌ์šฉ์ž ๊ฒฝํ—˜์„ ํ–ฅ์ƒํ•  ์ˆ˜ ์žˆ๋‹ค.

 

โœจ handleKeyUp

// selected์˜ ์ดˆ๊ธฐ๊ฐ’์€ -1 (์•„๋ฌด๊ฒƒ๋„ ์„ ํƒ๋˜์ง€ ์•Š์€ ์ƒํƒœ)
const [selected, setSelected] = useState(-1);

const handleKeyUp = (e) => {
    if (hasText) { // input ๊ฐ’์ด ์žˆ์„ ๋•Œ๋งŒ ๋™์ž‘

      // 1. ๋งˆ์ง€๋ง‰ ์ธ๋ฑ์Šค๊นŒ์ง€ ๊ฐ€๋ฉด ๋” ์ด์ƒ ์ด๋™ํ•˜์ง€ ์•Š๋Š” ๋ฐฉ๋ฒ•
      if (e.key === "ArrowDown" && selected < options.length - 1) {
        // option์ด 5๊ฐœ์ผ ๊ฒฝ์šฐ, ์ธ๋ฑ์Šค๋Š” 0-4๊นŒ์ง€
        // selected๊ฐ€ 4๊ฐ€ ๋˜๋ฉด ๋”์ด์ƒ ์ฆ๊ฐ€ํ•˜์ง€ ์•Š์Œ
        setSelected(selected + 1);
      }

      // 2. ๋งˆ์ง€๋ง‰ ์ธ๋ฑ์Šค๊นŒ์ง€ ๊ฐ€๋ฉด ์ฒ˜์Œ์œผ๋กœ ๋Œ์•„๊ฐ€๋Š” ๋ฐฉ๋ฒ•
      /*
      if (e.key === "ArrowDown" ) {
        if (selected < options.length - 1) {
          setSelected(selected + 1);
        } else if (selected === options.length - 1) {
          setSelected(0);
        }
      }
      */

      if (e.key === "ArrowUp" && selected >= 0) {
        // selected๊ฐ€ 0์ผ ๊ฒฝ์šฐ -1์ด ๋˜๊ณ ,
        // selected๊ฐ€ -1์ผ ๊ฒฝ์šฐ ๋” ์ด์ƒ ๋™์ž‘ํ•˜์ง€ ์•Š์Œ
        setSelected(selected - 1);
      }

      if (e.key === "Enter" & selected >= 0) {
        handleDropDownClick(options[selected]);
        setSelected(-1); // seleccted ๊ฐ’ ์ดˆ๊ธฐํ™” 
      }
  }
};

๐Ÿ’ฌ Advanced Challenge ์•ˆ์˜ Advanced ์˜€๋˜ dropdown ํ•ญ๋ชฉ์„ ์„ ํƒํ•˜๊ณ , Enter ํ‚ค ์ž…๋ ฅ ์‹œ input๊ฐ’์„ ์„ ํƒ๋œ dropdown ํ•ญ๋ชฉ์˜ ๊ฐ’์œผ๋กœ ๋ณ€๊ฒฝํ•˜๋Š” handleKeyUp ํ•จ์ˆ˜๋ฅผ ๋งŒ๋“œ๋Š” ๋ถ€๋ถ„์ด ์ œ์ผ ์–ด๋ ค์› ์—ˆ๋‹ค.

 

โœจ handleInputChange

const handleInputChange = (event) => {

    setInputValue(event.target.value);
    setHasText(true);
    setOptions( deselectedOptions.filter((el) => el.includes(event.target.value)) );

    // ๋Œ€์†Œ๋ฌธ์ž ๊ตฌ๋ถ„์—†์ด ํ•„ํ„ฐ
    // setOptions( deselectedOptions.filter((el) => el.toLowerCase().includes(event.target.value.toLowerCase())) );

    // ์˜คํ›„ ๋ผ์ด๋ธŒ์„ธ์…˜ ์ฝ”๋“œ
    // startsWith : ํŠน์ • ๋ฌธ์ž๋กœ ์‹œ์ž‘ํ•˜๋Š”์ง€ ํ™•์ธํ•˜์—ฌ ๊ฒฐ๊ณผ๋ฅผ true ๋˜๋Š” false๋กœ ๋ฐ˜ํ™˜
    // setOptions(deselectedOptions.filter((option) => option.startsWith(event.target.value)))
};

๐Ÿ’ฌ ๋Œ€์†Œ๋ฌธ์ž ๊ตฌ๋ถ„์—†์ด ํ•„ํ„ฐํ•˜๋Š” ๋ฐฉ๋ฒ•๊ณผ startWith๋ฅผ ์‚ฌ์šฉํ•œ ํ•„ํ„ฐ๋งํ•˜๋Š” ๋ฐฉ๋ฒ•์€ ์ƒ๊ฐํ•˜์ง€ ๋ชปํ–ˆ์—ˆ๋Š”๋ฐ, ๋ผ์ด๋ธŒ์„ธ์…˜์„ ํ†ตํ•ด ์•Œ๊ฒŒ ๋˜์—ˆ๋‹ค.

์ข€ ๋” ์ƒ๊ฐํ•ด๋ณด๋‹ˆ ๐Ÿค” ๊ฒ€์ƒ‰์„ ํ•  ๋•Œ ๋Œ€์†Œ๋ฌธ์ž์˜ ๊ตฌ๋ถ„์ด ์—†์—ˆ๋˜ ๊ฒƒ ๊ฐ™๊ณ , ๋Œ€๋ถ€๋ถ„์€ ํŠน์ • ๋ฌธ์ž๊ฐ€ ํฌํ•จ๋œ ๊ฒ€์ƒ‰์–ด๊ฐ€ ์•„๋‹Œ ํŠน์ • ๋ฌธ์ž๋กœ ์‹œ์ž‘ํ•˜๋Š” ๊ฒ€์ƒ‰์–ด๊ฐ€ ๋…ธ์ถœ๋˜์—ˆ๋˜ ๊ฒƒ ๊ฐ™๋‹ค..!๐Ÿ’ก

 

๐Ÿ’ฌ ๊ทธ๋ฆฌ๊ณ  ์ˆ˜์—…์‹œ๊ฐ„์— ๋ˆ„๊ตฐ๊ฐ€ ํ•œ๊ธ€ ๊ฒ€์ƒ‰์‹œ ์ž์Œ๋งŒ ์ž…๋ ฅํ•ด๋„ ํฌํ•จ๋œ ๋ฌธ์ž์—ด์ด ๊ฒ€์ƒ‰๋˜๋Š” ๋ฐฉ๋ฒ•์„ ์งˆ๋ฌธํ–ˆ์—ˆ๋‹ค. ์ด๊ฒƒ ๋˜ํ•œ ์ƒ๊ฐํ•ด๋ณด๋‹ˆ ์ž์Œ, ๋ชจ์Œ๋ณ„๋กœ ๊ฒ€์ƒ‰์ด ๊ฐ€๋Šฅํ•ด์•ผ ํ•œ๋‹ค๋Š” ์ƒ๊ฐ์ด ๋“ค์—ˆ๋‹ค. 

๊ทธ๋ž˜์„œ ํ•œ๊ธ€๋ฐ์ดํ„ฐ๋ฅผ ์ž์Œ, ๋ชจ์Œ ๋ณ„๋กœ ๊ฒ€์ƒ‰ํ•˜๊ณ  ์‹ถ์œผ๋ฉด ํ•œ๊ธ€ ์œ ๋‹ˆ์ฝ”๋“œ ์ž์†Œ๋ถ„๋ฆฌ๋ฅผ ํ•ด์•ผํ•œ๋‹ค๊ณ  ํ–ˆ๋‹ค. 

์˜ˆ๋ฅผ ๋“ค์–ด "๊ณจ๋™ํ’ˆ" ๊ฒ€์ƒ‰์‹œ ใ„ฑใ…—ใ„นใ„ทใ…—ใ…‡ใ…ใ…œใ… ์ด๋ ‡๊ฒŒ ์ž์†Œ๋ถ„๋ฆฌ๋ฅผ ์‹œํ‚ค๋Š” ๊ฒƒ์ด๋‹ค. 

๊ณจ๋™ํ’ˆ (searchData: [ใ„ฑ,ใ…—,ใ„น,ใ„ท,ใ…—,ใ…‡,ใ…,ใ…œ,ใ…])

๊ตฌํ˜„ํ•ด๋ณด๊ณ  ์‹ถ๊ธฐ๋Š” ํ•œ๋ฐ, ๋‹ค์Œ ์ง„๋„๊ฐ€ ๋ฐ”๋น ์„œ ์ผ๋‹จ์€ ํŒจ์Šคํ•˜๊ณ  ๋ฉ”๋ชจ๋งŒ ํ•ด๋‘์—ˆ๋‹ค. ๋‹ด์— ๊ผญ ํ•ด๋ด์•ผ์ง€..!

 

6. ClickToEdit

ClickToEdit ์ปดํฌ๋„ŒํŠธ๋Š” input ์ฐฝ์„ ํด๋ฆญํ•˜๋ฉด ์ˆ˜์ •์ด ๊ฐ€๋Šฅํ•˜๊ณ , input ์ฐฝ์ด ์•„๋‹Œ ๋‹ค๋ฅธ ๊ณณ์„ ํด๋ฆญํ•˜๋ฉด ์ˆ˜์ •ํ•œ ๋‚ด์šฉ์ด ๋ฐ˜์˜๋˜๋Š” ๊ธฐ๋Šฅ์„ ๊ฐ€์ง„ ์ปดํฌ๋„ŒํŠธ์ด๋‹ค.

 

ClickToEdit์€ ์ •๋ง ๋ฌด๋‚œํ•˜๊ฒŒ ๊ตฌํ˜„ ์™„๋ฃŒํ•ด์„œ ํŠน๋ณ„ํžˆ ์–ด๋ ค์šด ๋ถ€๋ถ„์€ ์—†์—ˆ๋‹ค. 

๋Œ€์‹  UI๊ฐ€ ์ข€ ๋ณ„๋กœ๋ผ์„œ CSS๋ฅผ ๊น”๋”ํ•˜๊ฒŒ ์ˆ˜์ •ํ•ด์„œ ์ข€ ๋” ๋ณด๊ธฐ์ข‹๊ฒŒ ๋งŒ๋“ค์—ˆ๋‹ค.

 

 ๊ตฌํ˜„ํ•œ๊ฑธ ํ…Œ์ŠคํŠธํ•˜๋‹ค๊ฐ€ ํ•œ๊ฐ€์ง€ ๋ฌธ์ œ๋ฅผ ๋ฐœ๊ฒฌํ–ˆ๋Š”๋ฐ, ์•„๋ž˜์ฒ˜๋Ÿผ ์•„๋ฌด๊ฒƒ๋„ ์ž…๋ ฅํ•˜์ง€ ์•Š์€ ์ƒํƒœ๋กœ ๋งˆ์šฐ์Šค๋ฅผ Blur ํ•˜๊ฒŒ ๋˜๋ฉด ๋‹ค์‹œ ์ˆ˜์ •์ด ์•ˆ๋˜๋Š” ๋ถ€๋ถ„์ด์—ˆ๋‹ค.

 

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

 ์žฌ์ž…๋ ฅ์ด ์•ˆ๋˜์—ˆ๋˜ ์ด์œ ๋Š” ์ˆ˜์ •์„ ํ•˜๊ธฐ ์œ„ํ•ด ํด๋ฆญ์„ ํ•˜๋Š” ๋ถ€๋ถ„์ธ span ์š”์†Œ์˜ ํฌ๊ธฐ๊ฐ€ ์‚ฌ๋ผ์ง€๋ฉด์„œ ํด๋ฆญํ•  ๋ถ€๋ถ„์ด ์—†์–ด์ง„ ๊ฒƒ์ด ๋ฌธ์ œ์˜€๋‹ค. ๊ทธ๋ž˜์„œ ๊ฐ„๋‹จํ•˜๊ฒŒ span ์š”์†Œ์˜ ํฌ๊ธฐ๋ฅผ ์ง€์ •ํ•ด์ฃผ๋ฉด ๊ฐ„๋‹จํ•˜๊ฒŒ ํ•ด๊ฒฐํ•  ์ˆ˜ ์žˆ๋‹ค.

 

export const InputBox = styled.div`
  /* text-align: center; */
  display: inline-block;
  width: 200px;
  height: 40px;
  line-height: 40px; 
  border: 1px #bbb dashed;
  border-radius: 10px;
  margin-left: 1rem;

  & span {
    display:inline-block;
    width: 100%;
    height: 100%;
    cursor: pointer;
  }
`;

๊ทธ๋ž˜์„œ ์ด๋ ‡๊ฒŒ styled component๋กœ ๊ตฌํ˜„ํ•œ InputBox ์ปดํฌ๋„ŒํŠธ ํ•˜์œ„์˜ span ์š”์†Œ์— ํฌ๊ธฐ๋ฅผ ์ง€์ •ํ•ด ์ฃผ์—ˆ๋‹ค. 

 

 


๐ŸŒ™  ์˜ค๋Š˜์˜ ํšŒ๊ณ 

 react custom component advanced ๊นŒ์ง€ ์™„๋ฃŒํ–ˆ๋‹ค. ์ปดํฌ๋„ŒํŠธ๋ฅผ ์ง์ ‘ ๊ตฌํ˜„ํ•˜๋Š” ์ž‘์—…์ด ๊ฝค ์žฌ๋ฏธ์žˆ์—ˆ๊ณ , ๋‹ค๋ฅธ ์ปดํฌ๋„ŒํŠธ๋„ ์ง์ ‘ ๋งŒ๋“ค์–ด๋ณด๋ฉด ์ข‹์„ ๊ฒƒ ๊ฐ™๋‹ค๋Š” ์ƒ๊ฐ์ด ๋“ค์—ˆ๋‹ค. ๋ฆฌ๋•์Šค๋ฅผ ๋ฌด๋‚œํžˆ ๋„˜๊ธด๋‹ค๋ฉด, ์ฃผ๋ง์— ํ•œ ๋ฒˆ ๋„์ „ํ•ด ๋ณด๋Š” ๊ฒƒ๋„ ์ข‹์„ ๊ฒƒ ๊ฐ™๋‹ค๋Š” ์ƒ๊ฐ์ด ๋“ค์—ˆ๋‹ค. ๐Ÿ™‚

 ์˜ค๋Š˜ ๋ฐค์—” ๋‚ด์ผ redux ํ•™์Šต์„ ์œ„ํ•ด ์˜ˆ์Šต ์ข€ ํ•ด์•ผ๊ฒ ๋‹ค. ๋ฆฌ๋•์Šค๋„ ์ด์ „์— ๊ณต๋ถ€๋ฅผ ํ•˜๊ธด ํ–ˆ๋Š”๋ฐ, ์ฐ์–ด๋จน๊ธฐ ์‹์œผ๋กœ ํ•ด์„œ ๊ฑฐ์˜ ๊ธฐ์–ต๋„ ์•ˆ๋‚˜๋Š” ๋“ฏ ํ•˜๋‹ค. ์ด๋ฒˆ์—” ์ œ๋Œ€๋กœ ๊ณต๋ถ€ํ•ด์•ผ์ง€!

๋ฐ˜์‘ํ˜•