Skip to content

dition0221/react_master_class

Folders and files

NameName
Last commit message
Last commit date

Latest commit

ย 

History

71 Commits
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 

Repository files navigation

React - Master Class

React๋ฅผ ๋”์šฑ ์‹ฌ์ธต์ ์œผ๋กœ ๊ตฌํ˜„ํ•ฉ๋‹ˆ๋‹ค.

React :
Framework :
Animation :


  • 23-08-17 : #1.0 ~ #2.2 / Styled-Components(1)
    • ํŒจํ‚ค์ง€ : 'styled-components'
      • React ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์—์„œ ์ปดํฌ๋„ŒํŠธ ๊ธฐ๋ฐ˜ ์Šคํƒ€์ผ๋ง์„ ์œ„ํ•œ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ
      • JavaScript ์ฝ”๋“œ ์•ˆ์—์„œ ์Šคํƒ€์ผ์„ ์ •์˜ํ•˜๊ณ , ์ปดํฌ๋„ŒํŠธ์™€ ํ•จ๊ป˜ ์‚ฌ์šฉ ๊ฐ€๋Šฅ
      • ์‚ฌ์šฉ๋ฒ•
        • import๊ตฌ๋ฌธ : import styled from "styled-components";
        • ๊ธฐ๋ณธํ˜• : const ์ปดํฌ๋„ŒํŠธ๋ช… = styled.HTMLํƒœ๊ทธ๋ช…`CSS์ฝ”๋“œ`;
        • props ์‚ฌ์šฉ
          • CSS : ${(์ธ์ž๋ช…) => ์ธ์ž๋ช….prop๋ช…}
            • ์ธ์ž๋ช…์€ ์•„๋ฌด๊ฑฐ๋‚˜ ์ƒ๊ด€์—†์œผ๋‚˜, ์ฃผ๋กœ 'props'๋กœ ์‚ฌ์šฉ
          • ์ปดํฌ๋„ŒํŠธ : <์ปดํฌ๋„ŒํŠธ๋ช… prop๋ช…=prop๊ฐ’ />
        • ์ด๋ฏธ ๋งŒ๋“ค์–ด์ง„ ์ปดํฌ๋„ŒํŠธ๋กœ๋ถ€ํ„ฐ ํ™•์žฅ ๊ฐ€๋Šฅ
          • ๊ธฐ๋ณธํ˜• : const ์ปดํฌ๋„ŒํŠธ๋ช… = styled(๊ธฐ์กด์ปดํฌ๋„ŒํŠธ๋ช…)`...`;
      • ์ž๋™ ์™„์„ฑ ๊ธฐ๋Šฅ 'vscode-styled-components' ํ™•์žฅํ”„๋กœ๊ทธ๋žจ ์‚ฌ์šฉ
  • 23-08-18 : #2.3 ~ #3.1 / Styled-Components(2) & Set up TypeScript
    • styled-components
      • ์ปดํฌ๋„ŒํŠธ์˜ ์Šคํƒ€์ผ์€ ๊ทธ๋Œ€๋กœ ์‚ฌ์šฉํ•˜๋˜, HTMLํƒœ๊ทธ๋งŒ์„ ๋ฐ”๊พธ๊ณ  ์‹ถ์„ ๋•Œ
        • ์ปดํฌ๋„ŒํŠธ์—์„œ 'as="HTMLํƒœ๊ทธ๋ช…"' ์†์„ฑ์„ ์‚ฌ์šฉ
      • ์ปดํฌ๋„ŒํŠธ ์ƒ์„ฑ ์‹œ ์†์„ฑ๊ฐ’์„ ์„ค์ •ํ•  ์ˆ˜ ์žˆ์Œ
        • ๊ธฐ๋ณธํ˜• : const ์ปดํฌ๋„ŒํŠธ๋ช… = styled.HTMLํƒœ๊ทธ๋ช….attrs({์†์„ฑ๊ฐ’๋“ค})`...`;
        • 'attrs'๋„ props๋ฅผ ์‚ฌ์šฉํ•ด ์ปค์Šคํ…€๋งˆ์ด์ง• ๊ฐ€๋Šฅ
      • ์• ๋‹ˆ๋ฉ”์ด์…˜
        • import๋ฌธ : import { keyframes } from "styled-components";
        • ๊ธฐ๋ณธํ˜• : const ๋ณ€์ˆ˜๋ช… = keyframes`...`;
        • ์• ๋‹ˆ๋ฉ”์ด์…˜ ์ ์šฉ์€ ๊ธฐ์กด CSS ๋ฐฉ์‹๊ณผ ๋™์ผ
      • ์„ ํƒ์ž(pseudo selector)
        • ํ•˜์œ„ ์„ ํƒ์ž๊ฐ€ ์ผ๋ฐ˜ HTMLํƒœ๊ทธ ์ด๋”๋ผ๋„ ์„ ํƒ ๊ฐ€๋Šฅ (SCSS์™€ ๊ตฌ๋ฌธ์ด ๋น„์Šทํ•จ)
        • ํ•˜์œ„ ์„ ํƒ์ž๊ฐ€ ์ปดํฌ๋„ŒํŠธ('as'๋ฅผ ์‚ฌ์šฉํ•˜๋”๋ผ๋„) ์‚ฌ์šฉ ๊ฐ€๋Šฅ
          • '${์ปดํฌ๋„ŒํŠธ๋ช…}'์œผ๋กœ ์‚ฌ์šฉ
        • '&' ๊ธฐํ˜ธ๋Š” ์ž๊ธฐ ์ž์‹ ์„ ๊ฐ€๋ฆฌํ‚ด
      • theme : ๊ธฐ๋ณธ์ ์œผ๋กœ ๋ชจ๋“  ์ƒ‰์ƒ๋“ค์„ ๊ฐ€์ง€๊ณ  ์žˆ๋Š” object
        • ๋ชจ๋“  ์ƒ‰์ƒ๋“ค์„ ํ•˜๋‚˜์˜ object ์•ˆ์— ๋„ฃ์–ด๋†จ๊ธฐ ๋•Œ๋ฌธ์— ๋งค์šฐ ์œ ์šฉํ•จ
        • ์ถ”ํ›„ ์ƒ‰์ƒ๋“ค์„ ๋ฐ”๊ฟ€ ๋•Œ ํ•ด๋‹น object๋งŒ ๋ฐ”๊ฟ”์ฃผ๋ฉด ๋˜๊ธฐ ๋•Œ๋ฌธ
        • ์„ค์ •๋ฒ•
          1. 'index'ํŒŒ์ผ์—์„œ 'import { ThemeProvider } from "styled-components";'
          2. ์‚ฌ์šฉํ•  ์ปดํฌ๋„ŒํŠธ๋ฅผ '<ThemeProvider>'๋กœ ๊ฐ์‹ธ์ฃผ๊ธฐ
          3. '<ThemeProvider>'์— 'theme' ์†์„ฑ ๋ถ€์—ฌํ•˜๊ธฐ
        • ์‚ฌ์šฉ๋ฒ•
          • 'styled-components'์—์„œ 'props.theme' ๊ฐ์ฒด๋ฅผ ์ด์šฉํ•˜์—ฌ ์‚ฌ์šฉ
          • 'theme'์—์„œ ์‚ฌ์šฉํ•œ ํ”„๋กœํผํ‹ฐ๋ช…์„ ์‚ฌ์šฉํ•ด์•ผ ํ•จ
          • 'theme' ๊ต์ฒด ์‹œ '<ThemeProvider>'์˜ 'theme' ์†์„ฑ๊ฐ’๋งŒ ๊ต์ฒดํ•˜๋ฉด ๋จ
    • TypeScript : JavaScript๋ฅผ ๊ธฐ๋ฐ˜์œผ๋กœ ํ•œ ํ”„๋กœ๊ทธ๋ž˜๋ฐ ์–ธ์–ด, compileํ•˜์—ฌ ํ‰๋ฒ”ํ•œ JavaScript๊ฐ€ ๋จ
      • ์„ค์น˜๋ฒ•
        • ์ƒˆ๋กœ์šด ํ”„๋กœ์ ํŠธ ์ƒ์„ฑ : 'npx create-react-app ํด๋”๋ช… --template typescript'
        • ๊ธฐ์กด ํ”„๋กœ์ ํŠธ์— TS ์ถ”๊ฐ€ : 'npm i --save typescript @types/node @types/react @types/react-dom @types/jest'
      • TS๊ฐ€ ํŒจํ‚ค์ง€๋ฅผ ์•Œ์ง€ ๋ชปํ•  ๋•Œ
        • ๋ช‡๋ช‡ ํŒจํ‚ค์ง€๋Š” JS๋กœ ๋งŒ๋“ค์–ด์กŒ๊ธฐ ๋•Œ๋ฌธ
        • 'npm i -D @types/ํŒจํ‚ค์ง€๋ช…'์„ ์‹คํ–‰ํ•ด ์„ค์น˜
      • 'index.tsx'์—์„œ root ์ฝ”๋“œ๊ฐ€ error ๋‚  ์‹œ ์•„๋ž˜์˜ ์ฝ”๋“œ๋กœ ์ˆ˜์ • (+ as HTMLElement)
        • const root = ReactDOM.createRoot(document.getElementById("root") as HTMLElement);
  • 23-08-21 : #3.2 ~ #4.2 / TypeScript + React-Router-V6(1)
    • TypeScript
      • React Component
        • Component๊ฐ€ ํ•„์š”๋กœ ํ•˜๋Š” prop์„ TS์—๊ฒŒ ์„ค๋ช…ํ•ด์•ผ ํ•จ
        • interface : ๊ฐ์ฒด ๋ชจ์–‘(object shape)์„ TS์—๊ฒŒ ์„ค๋ช…ํ•ด์ฃผ๋Š” TS์˜ ๊ฐœ๋…
          • ์„ ์–ธ ๊ธฐ๋ณธํ˜• : interface ์ธํ„ฐํŽ˜์ด์Šค๋ช… { ... }
          • ์‚ฌ์šฉ ๊ธฐ๋ณธํ˜• : ':ํƒ€์ž…๋ช…'
          • 'styled-components'์—์„œ prop์„ ๋ฐ›์œผ๋ ค๋ฉด, ํƒ€์ž…์„ ์„ ์–ธํ•ด ์ฃผ์–ด์•ผ ํ•จ
            • ๊ธฐ๋ณธํ˜• : const ์ปดํฌ๋„ŒํŠธ๋ช… = styled.HTMLํƒœ๊ทธ๋ช…<ํƒ€์ž…๋ช…>`...`;
      • ์„ ํƒ์ (optional) props
        • '?'๊ธฐํ˜ธ๋ฅผ ์‚ฌ์šฉํ•ด ์„ ํƒ์  prop ์„ค์ • ๊ฐ€๋Šฅ
        • ๋ณ‘ํ•ฉ์—ฐ์‚ฐ์ž '??' : 'null' ๋˜๋Š” 'undefined'์ผ ๋•Œ ๊ธฐ๋ณธ๊ฐ’ ์ง€์ • ๊ฐ€๋Šฅ
      • React State
        • TS๊ฐ€ 'useState'์˜ ์ดˆ๊นƒ๊ฐ’์„ ๋ณด๊ณ , ์ž๋™์ ์œผ๋กœ ํƒ€์ž…์„ ์ถ”๋ก ํ•จ
        • ๊ฐ€๋” 2๊ฐœ ์ด์ƒ์˜ ํƒ€์ž…์„ ์‚ฌ์šฉํ•˜๋Š” ๊ฒฝ์šฐ, ์ง์ ‘ ํƒ€์ž…์„ ์„ ์–ธํ•ด ์ฃผ์–ด์•ผ ํ•จ
          • ๊ธฐ๋ณธํ˜• : const [๋ณ€์ˆ˜๋ช…, ํ•จ์ˆ˜๋ช…] = useState<ํƒ€์ž…๋ช…>(์ดˆ๊นƒ๊ฐ’);
      • React Event
        • 'addEventListener'์— ์ธ์ž๋กœ ์‚ฌ์šฉํ•˜๋Š” 'event'์— ํƒ€์ž…์„ ์„ค๋ช…ํ•ด์•ผ ํ•จ
  • 23-08-22 : #5.0 ~ #5.3 / React-Router + createGlobalStyle + fetchAPI
    • React-Router v6
      • ์„ค์ •๋ฒ•
        1. '/src/routes' ํด๋”์— ํ™”๋ฉด์— ๋ณด์—ฌ์ค„ ์ปดํฌ๋„ŒํŠธ ํŒŒ์ผ๋“ค์„ ์ƒ์„ฑํ•˜๊ธฐ
        2. '/src/Router.tsx' ๋ผ์šฐํ„ฐ ํŒŒ์ผ ์ƒ์„ฑ ๋ฐ ์„ค์ •ํ•˜๊ธฐ
          • { BrowserRouter, Routes, Route } ๋“ฑ
        3. ๋ผ์šฐํ„ฐ ํŒŒ์ผ์„ ๋ Œ๋”๋งํ•˜๊ธฐ
          • 'App.tsx'์—์„œ <Router />๋ฅผ returnํ•˜์—ฌ ๋ Œ๋”๋ง
      • 'useParams()' : URL ํŒŒ๋ผ๋ฏธํ„ฐ ๊ฐ’(object)์„ ๋ฐ›์„ ์ˆ˜ ์žˆ์Œ
      • <Link> : React-Router ๋‚ด์—์„œ ํŽ˜์ด์ง€๋ฅผ ์ด๋™ํ•˜๋Š” ํƒœ๊ทธ
        • ๊ธฐ๋ณธํ˜• : <Link to="์ด๋™ํ• URL">๋‚ด์šฉ</Link>
        • CSS์—์„œ๋Š” 'Link' ๋Œ€์‹  'a'ํƒœ๊ทธ๋กœ ์‚ฌ์šฉ ๊ฐ€๋Šฅ
    • 'styled-components'์—์„œ์˜ ์ „์—ญ ์Šคํƒ€์ผ๋ง
      • 'createGlobalStyle' ํ”„๋กœํผํ‹ฐ๋ฅผ ์‚ฌ์šฉํ•ด ๋ Œ๋”๋ง ์‹œ ์ „์—ญ ์Šค์ฝ”ํ”„์— ์Šคํƒ€์ผ ์‚ฌ์šฉ
        • ๊ธฐ๋ณธํ˜• : const ์ปดํฌ๋„ŒํŠธ๋ช… = createGlobalStyle` ... `;
      • '<์ปดํฌ๋„ŒํŠธ๋ช… />'์„ ์‚ฌ์šฉํ•ด return
        • ํฐํŠธ ์‚ฌ์šฉ ์‹œ '@import'๋ฌธ์ด ์ œ๋Œ€๋กœ ์ ์šฉ๋˜์ง€ ์•Š์œผ๋ฏ€๋กœ, 'index.html'์˜ <head>์— ๋„ฃ์€ ํ›„ ์‚ฌ์šฉ
    • <Fragment> : ์ผ์ข…์˜ ์œ ๋ น ์ปดํฌ๋„ŒํŠธ
      • ๋ถ€๋ชจ element ์—†์ด ์„œ๋กœ ๋ถ™์–ด์žˆ๋Š” ๋งŽ์€ ์ปดํฌ๋„ŒํŠธ๋“ค์„ returnํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•ด์คŒ
        • <div> element ์‚ฌ์šฉ ์—†์ด ๋ Œ๋”๋ง
        • ๋ฌด์ˆ˜ํ•œ <div>๊ฐ€ ์‚ฌ์šฉ๋˜๋Š” ๊ฒƒ์„ ๋ฐฉ์ง€ํ•จ
      • ์ฃผ๋กœ ๋นˆ ํƒœ๊ทธ(<></>)๋กœ ์‚ฌ์šฉํ•จ
    • fetch API
      • API๋ฅผ ํ†ตํ•ด ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ ธ์˜ฌ ๋•Œ TS์—๊ฒŒ ๋ฐ์ดํ„ฐ์˜ ํƒ€์ž…์„ ์•Œ๋ ค์ฃผ์–ด์•ผ ํ•จ (interface)
      • 'axios'ํŒจํ‚ค์ง€ ์‚ฌ์šฉ ์‹œ json ํ˜•์‹์œผ๋กœ ๋ฐ”๋กœ ๊ฐ€์ ธ์˜ด
        • ๊ธฐ๋ณธํ˜• : const ๋ณ€์ˆ˜๋ช… = await axios("URL์ฃผ์†Œ");
    • ์ฆ‰์‹œ ์‹คํ–‰ ํ•จ์ˆ˜ ํ‘œํ˜„ (IIFE; Immediately Invoked Function Expression)
      • ์ •์˜๋˜์ž๋งˆ์ž ์ฆ‰์‹œ ์‹คํ–‰๋˜๋Š” ํ•จ์ˆ˜ (์„ ์–ธ ํ›„ ์‹คํ–‰ํ•  ํ•„์š” ์—†์Œ)
      • ๊ธฐ๋ณธํ˜• : (ํ•จ์ˆ˜์„ ์–ธ)();
  • 23-08-23 : #5.4 ~ #5.8 / Link state + Nested Routes + useMatch
    • <Link> state : ํ™”๋ฉด์— ๋ณด์ด์ง€ ์•Š๋Š” ๋ฐฉ์‹์œผ๋กœ ๋‹ค๋ฅธ ํŽ˜์ด์ง€์— ๋ฐ์ดํ„ฐ๋ฅผ ๋ณด๋‚ด๋Š” ๋ฐฉ๋ฒ•
      • 'state' ์†์„ฑ์„ ์‚ฌ์šฉํ•ด object ํ˜•์‹์œผ๋กœ ๋ฐ์ดํ„ฐ ์ „์†ก ๊ฐ€๋Šฅ
      • 'useLocation()'์„ ์‚ฌ์šฉํ•ด ๋ฐ์ดํ„ฐ๋ฅผ ์ˆ˜์‹ 
        • ๋ฐ›์€ ๋ฐ์ดํ„ฐ์˜ ํƒ€์ž…์„ TS์—๊ฒŒ ์„ค๋ช…ํ•ด์ฃผ์–ด์•ผ ํ•จ
        • react-router-dom v6๋ถ€ํ„ฐ 'useLocation()'์˜ ์ œ๋„ค๋ฆญ์„ ์ง€์›ํ•˜์ง€ ์•Š์Œ
          • 'as ์ธํ„ฐํŽ˜์ด์Šค๋ช…' ๋ฐฉ์‹์œผ๋กœ ์‚ฌ์šฉ
    • '?.' ์˜ต์…”๋„์ฒด์ด๋‹
      • ๊ฐ์ฒด์˜ ํ”„๋กœํผํ‹ฐ์— ์ ‘๊ทผ ์‹œ ํ•ด๋‹น ํ”„๋กœํผํ‹ฐ๊ฐ€ ์กด์žฌํ•˜์ง€ ์•Š๋Š” ๊ฒฝ์šฐ, Error๋ฅผ ๋ฐœ์ƒ์‹œํ‚ค์ง€ ์•Š๊ณ  'undefined'๋ฅผ ๋ฐ˜ํ™˜ํ•จ
    • Nested Routes : route ์•ˆ์— ์กด์žฌํ•˜๋Š” ๋˜ ๋‹ค๋ฅธ route
      • ์›น์‚ฌ์ดํŠธ์—์„œ ํƒญ์„ ์‚ฌ์šฉํ•  ๋•Œ ์œ ์šฉํ•จ (์Šคํฌ๋ฆฐ ์•ˆ์— ์„น์…˜์ด ๋งŽ์„ ๋•Œ ๋“ฑ)
      • ์ƒ์„ฑ๋ฒ• (์ž์‹ route๋ฅผ ๋ผ์šฐํ„ฐ ํŒŒ์ผ์— ์ž‘์„ฑํ•˜๋Š” ๋ฐฉ๋ฒ•)
        1. ๋ผ์šฐํ„ฐ ํŒŒ์ผ์—์„œ ๋ถ€๋ชจ <Route>์— ๊ฐ์‹ธ์„œ ์‚ฌ์šฉํ•˜๊ธฐ
          • ์ƒ๋Œ€๊ฒฝ๋กœ URL์„ ์ง€์›ํ•˜๋ฏ€๋กœ, ์ž์‹ route์˜ path๋Š” ์ƒ๋Œ€๊ฒฝ๋กœ๋ฅผ ์‚ฌ์šฉ
        2. ์ž์‹ route๊ฐ€ ์–ด๋””์— render๊ฐ€ ๋ ์ง€ ๋ถ€๋ชจ route ์ปดํฌ๋„ŒํŠธ์—์„œ '<Outlet />'์œผ๋กœ ํ‘œ์‹œํ•˜๊ธฐ
    • useMatch() : ํ˜„์žฌ URL ์œ„์น˜๋ฅผ ๊ธฐ์ค€์œผ๋กœ ์ง€์ •๋œ ๊ฒฝ๋กœ์— ๋Œ€ํ•œ ์ผ์น˜ ๋ฐ์ดํ„ฐ๋ฅผ ๋ฐ˜ํ™˜
      • ๊ธฐ๋ณธํ˜• : const ๋ณ€์ˆ˜๋ช… = useMatch("URL์ฃผ์†Œ");
        • import { useMatch } from "react-router-dom";
        • ์ƒ๋Œ€๊ฒฝ๋กœ URL ์‚ฌ์šฉ ๋ถˆ๊ฐ€๋Šฅ
      • ์‚ฌ์šฉ์ž๊ฐ€ ์„ ํƒํ•œ URL์— ์œ„์น˜ํ•˜๋ฉด object๋ฅผ ๋ฐ˜ํ™˜, ๊ทธ๋ ‡์ง€์•Š์œผ๋ฉด null์„ ๋ฐ˜ํ™˜
  • 23-08-26 : #5.9 ~ #5.11 / React-Query
    • React-Query
      • ํŽธ๋ฆฌํ•œ ๋ฐฉ์‹์œผ๋กœ ๋ฐ์ดํ„ฐ๋ฅผ fetch ํ•  ์ˆ˜ ์žˆ๋Š” ํŒจํ‚ค์ง€
        • ๊ธฐ์กด ๋ฐฉ์‹์ธ useEffect์™€ useState๋ฅผ ํ™œ์šฉํ•œ fetch API๋ฅผ ํ•˜์ง€ ์•Š์•„๋„ ๋จ
      • ์„ค์น˜๋ฒ• : 'npm i @tanstack/react-query'
      • ์„ค์ •๋ฒ•
        1. 'index.tsx'์—์„œ 'queryClient' ๊ฐ์ฒด ์ƒ์„ฑํ•˜๊ธฐ
        2. '<QueryClientProvider>' ์ƒ์„ฑ ํ›„ ๊ฐ์‹ธ์ฃผ๊ธฐ
      • ์‚ฌ์šฉ๋ฒ•
        1. fetcher ํ•จ์ˆ˜ ์ƒ์„ฑํ•˜๊ธฐ
          • ๋ฌด์กฐ๊ฑด fetch promise(json)๋ฅผ return ํ•ด์ฃผ์–ด์•ผ ํ•จ
        2. 'useQuery' Hook์„ ์‚ฌ์šฉํ•ด API ๋ฐ์ดํ„ฐ ๊ฐ€์ ธ์˜ค๊ธฐ
          • ๊ธฐ๋ณธํ˜• : const { isLoading, data } = useQuery<์ œ๋„ค๋ฆญ>([์ฟผ๋ฆฌํ‚ค๋ช…], fetcherํ•จ์ˆ˜, ?์˜ต์…˜);
            • queryKey : (string[]) query์˜ ๊ณ ์œ ์‹๋ณ„์ž
            • fetcherํ•จ์ˆ˜ : ๋งค๊ฐœ๋ณ€์ˆ˜ ํ•„์š” ์‹œ ์ต๋ช…ํ™”์‚ดํ‘œํ•จ์ˆ˜๋กœ ์ž‘์„ฑ
            • ์˜ต์…˜ : (object)
              • refetchInterval : (number) ์ž๋™์œผ๋กœ refetchํ•˜๋Š” ์‹œ๊ฐ„ ์ฃผ๊ธฐ๋ฅผ ์„ค์ •
            • isLoading : ๋กœ๋”ฉ์— ๋Œ€ํ•œ boolean๊ฐ’์„ return
            • data : fetch๊ฐ€ ๋๋‚œ ํ›„ ๋ฐ์ดํ„ฐ๋ฅผ ๋„ฃ์–ด์คŒ
      • [ํ•ต์‹ฌ] ๋‹ค๋ฅธ ํŽ˜์ด์ง€์— ๊ฐ”๋‹ค๊ฐ€ ๋‹ค์‹œ ๋Œ์•„์™€๋„ API๋ฅผ ์žฌ์š”์ฒญํ•˜์ง€ ์•Š์Œ
        • React-Query๊ฐ€ ๋ฐ์ดํ„ฐ๋ฅผ ์บ์‹œ์— ์ €์žฅํ•ด๋‘๊ธฐ ๋•Œ๋ฌธ
    • React-Query-Devtools
      • ์บ์‹œ์— ์กด์žฌํ•˜๋Š” Query๋ฅผ ๋ณผ ์ˆ˜ ์žˆ์Œ
        • React-Query์˜ ๋ชจ๋“  ๋‚ด๋ถ€ ๋™์ž‘์„ ์‹œ๊ฐํ™”ํ•˜๋Š” ๋ฐ ๋„์›€
        • ๋ฌธ์ œ ๋ฐœ์ƒ์‹œ ๋””๋ฒ„๊น… ์‹œ๊ฐ„์„ ์ ˆ์•ฝํ•  ์ˆ˜ ์žˆ์Œ
      • ๊ธฐ๋ณธ์ ์œผ๋กœ React-Query-Devtools๋Š” process.env.NODE_ENV === 'development'์ธ ๊ฒฝ์šฐ์—๋งŒ ๋ฒˆ๋“ค์— ํฌํ•จ๋˜๋ฏ€๋กœ, production build ์ค‘์— ์ œ์™ธํ•˜๋Š” ๊ฒƒ์— ๋Œ€ํ•ด ๊ฑฑ์ •ํ•  ํ•„์š” ์—†์Œ
      • ์„ค์น˜๋ฒ• : 'npm i @tanstack/react-query-devtools'
      • ์„ค์ • ๋ฐ ์‚ฌ์šฉ๋ฒ• : 'App.tsx'์—์„œ 'ReactQueryDevtools'๋ฅผ importํ•œ ํ›„ ์ปดํฌ๋„ŒํŠธ๋ฅผ ์‚ฌ์šฉ
        • 'initialIsOpen={true}' ์†์„ฑ ํ•„์ˆ˜
  • 23-08-28 : #5.12 ~ #5.16 / ApexCharts + React-Helmet
    • useOutletContext()
      • ์ค‘์ฒฉ๋œ ๋ผ์šฐํŠธ(Nested Routes)์—์„œ ๋ถ€๋ชจ์—์„œ ์ž์‹ ์ปดํฌ๋„ŒํŠธ์—๊ฒŒ ์ƒํƒœ(state)๋ฅผ ๊ณต์œ ํ•˜๊ธฐ ์œ„ํ•œ ๋ชฉ์ ์œผ๋กœ ์‚ฌ์šฉํ•˜๋Š” Hook
      • <Outlet /> ์‚ฌ์šฉ ์‹œ ํ•˜์œ„ Route์—๊ฒŒ ๋ณ€์ˆ˜๋ฅผ ๋„˜๊ฒจ์ค„ ์ˆ˜ ์žˆ๋Š” ๊ธฐ๋Šฅ
        • ์†ก์‹  ๊ธฐ๋ณธํ˜• : <Outlet context={{ ... }}> (object ํ˜•์‹์œผ๋กœ ์‚ฌ์šฉ)
        • ์ˆ˜์‹  ๊ธฐ๋ณธํ˜•
          • import { useOutletContext } from "react-router-dom";
          • const ๋ณ€์ˆ˜๋ช… = useOutletContext<์ œ๋„ค๋ฆญ>();
    • ApexCharts.js
      • API๋กœ ๋ฐ›์•„์˜จ ๋ฐ์ดํ„ฐ ๋“ฑ์„ ์‹œ๊ฐํ™” ํ•  ์ˆ˜ ์žˆ๋Š” ํŒจํ‚ค์ง€
      • ์„ค์น˜๋ฒ• : 'npm i react-apexcharts apexcharts'
      • ์‚ฌ์šฉ๋ฒ•
        • import ApexChart from "react-apexcharts";
        • <ApexChart ์†์„ฑ๋“ค />
          • type : ๊ทธ๋ž˜ํ”„ ํƒ€์ž… (string)
          • series : ๋ณด์—ฌ์ค„ ๋ฐ์ดํ„ฐ (object[]) { name: string, data: [] }
          • options : ๊ณต์‹๋ฌธ์„œ๋ฅผ ์ฐธ๊ณ ํ•˜์—ฌ ์‚ฌ์šฉ (object)
    • React-Helmet
      • ๋ฌธ์„œ์˜ <head>๋กœ ๋ Œ๋”๋งํ•˜๋Š” ์ปดํฌ๋„ŒํŠธํ˜• ํŒจํ‚ค์ง€
      • ์„ค์น˜๋ฒ• : 'npm i react-helmet'
      • ์‚ฌ์šฉ๋ฒ•
        • import { Helmet } from "react-helmet";
        • <Helmet> ... </Helmet>
      • 'Using UNSAFE_componentWillMount in strict mode is not recommended and may indicate bugs in your code.'์˜ Error ์‹œ 'react-helmet-async' ํŒจํ‚ค์ง€๋ฅผ ์‚ฌ์šฉ
        • 'App.tsx'์—์„œ <Router />๋ฅผ <HelmetProvider>๋กœ ๊ฐ์‹ธ์ค€ ํ›„ ์‚ฌ์šฉ
        • 'react-helmet' ํŒจํ‚ค์ง€๋„ ๋‹ค์šด ๋ฐ›์•„์•ผ ํ•จ
  • 23-08-29 : [Code Challenge] use ApexChart
  • 23-08-30 : #6.0 ~ #6.4 / Recoil Atom
    • Recoil
      • React์—์„œ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ์ƒํƒœ ๊ด€๋ฆฌ(state management) ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ
      • ์„ค์น˜๋ฒ• : 'npm i recoil'
      • ์„ค์ •๋ฒ• : 'index.tsx'์—์„œ <RecoilRoot>๋กœ ์•ฑ์„ ๊ฐ์‹ธ์ฃผ๊ธฐ
    • atom : ํŠน์ • ์ปดํฌ๋„ŒํŠธ์— ์ข…์†๋˜์ง€ ์•Š์œผ๋ฉฐ, global state๋ฅผ ์ €์žฅํ•˜๋Š” ๊ธฐ๋ณธ ๋‹จ์œ„
      • Recoil์—์„œ๋Š” state๊ฐ’์„ 'atom'์ด๋ผ๋Š” ๋ฒ„๋ธ”์— ๋‹ด์•„์„œ ์‚ฌ์šฉ
      • atom์ด ๋ณ€๊ฒฝ๋˜๋ฉด ์ปดํฌ๋„ŒํŠธ๋„ ๋ณ€๊ฒฝ๋œ ๊ฐ’์œผ๋กœ re-rendering ๋จ
      • ์‚ฌ์šฉ๋ฒ•
        1. 'atom'์„ ๊ด€๋ฆฌํ•˜๋Š” ํŒŒ์ผ ์ƒ์„ฑํ•˜๊ธฐ
          • '/src/atoms.ts'
        2. 'atom' ์ƒ์„ฑํ•˜๊ธฐ
          • import { atom } from "recoil";
          • ๊ธฐ๋ณธํ˜• : export const ๋ณ€์ˆ˜๋ช… = atom({ key: ํ‚ค๊ฐ’, default: ์ดˆ๊ธฐ๊ฐ’});
        3. [Read] ๋‹ค๋ฅธ ์ปดํฌ๋„ŒํŠธ์—์„œ 'atom' ์—ฐ๊ฒฐํ•˜๊ธฐ
          • ๊ธฐ๋ณธํ˜• : const ๋ณ€์ˆ˜๋ช… = useRecoilValue(์•„ํ†ฐ๋ช…);
        4. [Write] ๋‹ค๋ฅธ ์ปดํฌ๋„ŒํŠธ์—์„œ 'atom' ์ˆ˜์ •ํ•˜๊ธฐ
          • ๊ธฐ๋ณธํ˜• : const Setterํ•จ์ˆ˜ = useRecoilState(์•„ํ†ฐ๋ช…);
          • 'useState()'์ฒ˜๋Ÿผ ์‚ฌ์šฉํ•˜๋ฉด ๋จ
  • 23-08-31 : #6.5 ~ #6.7 / React-Hook-Form(1)
    • React Hook Form
      • React์—์„œ <form>์„ ๊ฐ„๋‹จํ•˜๊ฒŒ ์ œ์ž‘ํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋„์™€์ฃผ๋ฉฐ, ๊ฒ€์ฆ๊นŒ์ง€ ํ•  ์ˆ˜ ์žˆ๋Š” ํŒจํ‚ค์ง€
        • ๊ธฐ์กด React์—์„œ <form> ์ œ์ž‘ ์‹œ setState(), value, onChange, onSubmit ๋“ฑ์„ ์‚ฌ์šฉํ•ด์•ผ ํ–ˆ์Œ
      • ์„ค์น˜๋ฒ• : 'npm i react-hook-form'
      • ๊ธฐ๋ณธํ˜•
        • import { useForm} from "react-hook-form";
        • const { register, watch, handleSubmit, formState ๋“ฑ } = useForm<์ œ๋„ค๋ฆญ>();
      • register : <input>์˜ value์™€ onChange๋ฅผ ๋Œ€์ฒดํ•˜๋Š” ์†์„ฑ
        • name, onBlur, onChange, ref ๋“ฑ์„ ๊ฐ€์ง€๋Š” object๋ฅผ returnํ•˜๋Š” ํ•จ์ˆ˜
        • ์‚ฌ์šฉ๋ฒ• : <input {...register(์ด๋ฆ„, {๊ฒ€์ฆ ์†์„ฑ})} />
          • ES6 ๋ฌธ๋ฒ•์„ ์‚ฌ์šฉํ•ด register ํ•จ์ˆ˜๊ฐ€ ๋ฐ˜ํ™˜ํ•˜๋Š” ๊ฐ์ฒด๋ฅผ ๊ฐ€์ ธ๋‹ค๊ฐ€ props๋กœ ์‚ฌ์šฉ
          • HTML ๋ฟ๋งŒ์•„๋‹ˆ๋ผ JS์—์„œ๋„ ๊ฒ€์ฆ์„ ํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•จ
            • ์œ ํšจํ•˜์ง€ ์•Š์„ ์‹œ ์ž๋™์œผ๋กœ ํ•ด๋‹น element๋กœ focus ํ•ด์คŒ
        • ex. <input {...register("email", { required: true, minLength: 10 })} placeholder="Email" />
      • handleSubmit : <form>์˜ 'onSubmit'์„ ๋Œ€์ฒดํ•˜๊ณ , validation์„ ๋‹ด๋‹นํ•จ
        • ๊ธฐ์กด onSubmit์˜ 'event.preventDefault()์™€ setModifierํ•จ์ˆ˜'๋ฅผ ๋Œ€์ฒด
        • ์‚ฌ์šฉ๋ฒ• : <form onSubmit={handleSubmit(๋ฐ์ดํ„ฐ ์œ ํšจ ์‹œ ํ˜ธ์ถœํ•จ์ˆ˜, ?๋ฐ์ดํ„ฐ ๋ฌดํšจ ์‹œ ํ˜ธ์ถœ ํ•จ์ˆ˜)}>
      • watch : <form>์˜ ์ž…๋ ฅ๊ฐ’๋“ค์˜ ๋ณ€ํ™”๋ฅผ ๊ด€์ฐฐํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•ด์ฃผ๋Š” ํ•จ์ˆ˜
        • registerํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๋ชจ๋“  element๋“ค์˜ ๊ฐ’์„ object๋กœ ๋ฐ˜ํ™˜
        • ex. console.log(watch());
      • formState : ๋ฐ์ดํ„ฐ ๊ฒ€์ฆ์ด ์œ ํšจํ•˜์ง€ ์•Š์„ ์‹œ 'formState.errors'๋ฅผ ์ฐธ์กฐํ•ด error ๋‚ด์šฉ ํ™•์ธ ๊ฐ€๋Šฅ
        • ์–ด๋–ค ์ข…๋ฅ˜์˜ error๊ฐ€ ๋ฐœ์ƒํ–ˆ๋Š”์ง€ ์•Œ ์ˆ˜ ์žˆ์Œ
        • error ๋ฐœ์ƒ ์‹œ message๋ฅผ ๋ณด๋‚ผ ์ˆ˜ ์žˆ์Œ
        • ex. <input {...register("pw", { required: "PW is Required", minLength: { value: 5, message: "Your PW is too short" }})} />
  • 23-09-02 : #6.8 ~ #6.10 / React-Hook-Form(2)
    • React-Hook-Form
      • React-Hook-Form์—์„œ๋Š” register ์‚ฌ์šฉ ์‹œ ๋ฌธ์ž์—ด์„ return ํ•˜๋ฉด, error ๋ฉ”์‹œ์ง€๋ฅผ returnํ•œ๋‹ค๋Š” ๋œป
      • setValue : ํ•„๋“œ ๊ฐ’์„ ์—…๋ฐ์ดํŠธํ•˜๋Š” ํ•จ์ˆ˜
        • ๊ธฐ๋ณธํ˜• : const { setValue } = useForm();
        • ์‚ฌ์šฉ๋ฒ• : setValue(์ด๋ฆ„, ํ•„๋“œ๊ฐ’);
      • reset : <form>์˜ ๋ชจ๋“  ํ•„๋“œ๊ฐ’์„ ์ดˆ๊ธฐํ™”ํ•˜๋Š” ํ•จ์ˆ˜
        • ๊ธฐ๋ณธํ˜• : const { reset } = useForm();
        • ์‚ฌ์šฉ๋ฒ• : reset();
    • React-Hook-Form - ๊ฒ€์ฆ
      • ๊ฒ€์ฆ ์‹œ ์ •๊ทœ์‹(Regular Expression)์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Œ : 'pattern' ํ”„๋กœํผํ‹ฐ ์‚ฌ์šฉ
      • ๊ฒ€์ฆ ์กฐ๊ฑด๋งˆ๋‹ค message๋ฅผ ์ ์–ด๋†จ๋‹ค๋ฉด, error ๋ฌธ๊ตฌ๋ฅผ ํ™”๋ฉด์— ์ถœ๋ ฅ ๊ฐ€๋Šฅ
        • ์‚ฌ์šฉ์ž๊ฐ€ ์ œ์ถœํ•œ ์ดํ›„์—๋Š” message๊ฐ€ ์‹ค์‹œ๊ฐ„์œผ๋กœ ๋ณ€ํ•จ
        • 'useForm()'์— ์ œ๋„ค๋ฆญ์„ ๋ช…์‹œํ•˜์ง€ ์•Š์•˜์„์‹œ string์œผ๋กœ ํƒ€์ž…์„ ๋ช…์‹œํ•ด์ฃผ์–ด์•ผ ํ•จ (as string)
    • React-Hook-Form - ์ปค์Šคํ…€ ๊ฒ€์ฆ
      • 'handleSubmit()'์˜ ์ธ์ž๋กœ ์‚ฌ์šฉํ•˜๋Š” ์ฝœ๋ฐฑํ•จ์ˆ˜์— ์ปค์Šคํ…€ ๊ฒ€์ฆ์ด ๊ฐ€๋Šฅํ•จ
      • ๊ฒ€์ฆ ์ฝœ๋ฐฑํ•จ์ˆ˜์˜ ๋งค๊ฐœ๋ณ€์ˆ˜๋Š” ์ž๋™์œผ๋กœ <form>์˜ element๋“ค์„ ๋ฐ›์Œ
        • ํ•ด๋‹น ๋งค๊ฐœ๋ณ€์ˆ˜์˜ ํ”„๋กœํผํ‹ฐ๋ฅผ ์‚ฌ์šฉ
      • useForm()์˜ 'setError' ํ”„๋กœํผํ‹ฐ๋Š” ํŠน์ •ํ•œ error๋ฅผ ๋ฐœ์ƒ์‹œ์ผœ ์คŒ
        • ๊ธฐ๋ณธํ˜• : setError(๋ ˆ์ง€์Šคํ„ฐ๋ช…, { message: ์—๋Ÿฌ๋ฉ”์‹œ์ง€ });
        • interface์— ์˜ต์…˜ ํ•ญ๋ชฉ์„ ๋„ฃ์–ด์„œ, ์ถ”๊ฐ€์ ์ธ error๋ฅผ ํ‘œ๊ธฐํ•  ์ˆ˜ ์žˆ์Œ
        • <form>์—์„œ ์ž๋™์œผ๋กœ error ํ•ญ๋ชฉ์œผ๋กœ focus๋˜๊ฒŒ ํ•  ์ˆ˜ ์žˆ์Œ
          • setError()์˜ 3๋ฒˆ์งธ ๋งค๊ฐœ๋ณ€์ˆ˜๋กœ '{ shouldFocus: true }'๋ฅผ ๋ถ€์—ฌํ•˜์—ฌ ์ž‘๋™
      • register์˜ ๊ฒ€์ฆ ์†์„ฑ๋“ค ์ค‘ 'validate' ์˜ต์…˜์„ ์‚ฌ์šฉํ•ด ์ปค์Šคํ…€ ๊ทœ์น™์„ ๊ฒ€์‚ฌํ•  ์ˆ˜ ์žˆ์Œ
        • validate : ํ˜„์žฌ value๊ฐ’์„ ์ธ์ž๋กœ ๋ฐ›๋Š” ์ฝœ๋ฐฑํ•จ์ˆ˜๋ฅผ ๊ฐ’์œผ๋กœ ๊ฐ€์ง€๋ฉฐ, boolean๊ฐ’์„ ๋ฐ˜ํ™˜ํ•จ (๊ฒ€์ฆ์„ ํ†ต๊ณผ/๋ถˆํ†ต๊ณผ)
        • ์‚ผํ•ญ์กฐ๊ฑด์—ฐ์‚ฐ์ž(๋˜๋Š” ||)๋ฅผ ์‚ฌ์šฉํ•ด error ๋ฉ”์‹œ์ง€๋ฅผ return ํ•˜๋„๋ก ํ•จ
        • ์—ฌ๋Ÿฌ ํ•จ์ˆ˜(๊ฒ€์ฆ)๊ฐ€ ์žˆ๋Š” object ํ˜•ํƒœ๊ฐ€ ๋  ์ˆ˜ ์žˆ์Œ
        • async ๋น„๋™๊ธฐ๋กœ ๋งŒ๋“ค์–ด์„œ ์„œ๋ฒ„์—๋‹ค๊ฐ€ ํ™•์ธํ•˜๊ณ  ์‘๋‹ต์„ ๋ฐ›์„ ์ˆ˜ ์žˆ์Œ
  • 23-09-04 : #6.11 ~ #6.15 / To-Do List
    • Recoil - useRecoilState()
      • atom์„ 'useState()'์ฒ˜๋Ÿผ ์‚ฌ์šฉํ•˜๋Š” ๋ฉ”์„œ๋“œ
        • 'useRecoilValue()'์™€ 'useSetRecoilState()'๋ฅผ ๋”ฐ๋กœ ์‚ฌ์šฉํ•  ํ•„์š”๊ฐ€ ์—†์Œ
      • ๊ธฐ๋ณธํ˜• : const [๊ฐ’, ์„ธํ„ฐํ•จ์ˆ˜] = useRecoilState(์•„ํ†ฐ๋ช…);
    • ๋งค๊ฐœ๋ณ€์ˆ˜๋ฅผ ๊ฐ€์ง€๋Š” Event Listener ์‚ฌ์šฉ๋ฒ•
      1. element์—์„œ event๋ฅผ ์ต๋ช…ํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•ด ๋งค๊ฐœ๋ณ€์ˆ˜๋ฅผ ์ „๋‹ฌํ•˜๋Š” ๋ฐฉ๋ฒ•
        • ex. const onClick = (newCategory: IToDo["category"]) => { ย ย console.log("I wanna to", newCategory); }; <button onClick={() => onClick("DOING")}>Doing</button>
      2. element์˜ name ์†์„ฑ์„ ํ™œ์šฉํ•˜๋Š” ๋ฐฉ๋ฒ•
      • 'name' ์†์„ฑ์— ์ง์ ‘ ํƒ€์ž…์„ ์ค„ ์ˆ˜ ์—†๊ธฐ ๋•Œ๋ฌธ์—, 1๋ฒˆ ๋ฐฉ๋ฒ•์„ ์„ ํ˜ธ
      • ex. const onClick = (event: React.MouseEvent<HTMLButtonElement>) => { ย ย console.log("I wanna to", event.currentTarget.name); }; <button name="DOING" onClick={onClick}>Doing</button>
    • To-Do List์—์„œ ํ•˜๋‚˜์˜ to-do๋ฅผ ์ˆ˜์ •ํ•˜๋Š” ๋ฐฉ๋ฒ•
      • ๋ฐฐ์—ด์„ mutateํ•˜์ง€ ์•Š์œผ๋ฉด์„œ, 'useSetRecoilState()'๋กœ ์›ํ•˜๋Š” ํ•˜๋‚˜์˜ ๊ฐ’์„ ์ˆ˜์ •ํ•ด์•ผ ํ•จ
      1. 'id' ๋“ฑ์˜ ์†์„ฑ์„ ์‚ฌ์šฉํ•˜์—ฌ, ๋ฐฐ์—ด ์† ์›ํ•˜๋Š” element์˜ index ์ฐพ๊ธฐ
        • ๊ฐ’ ์ž์ฒด๋ฅผ ์ฐพ์„ ํ•„์š”๋Š” ์—†๊ณ , ๋ฐฐ์—ด index๊ฐ’๋งŒ ์•Œ๋ฉด ๋จ
        • ๋ฐฐ์—ด์˜ '.findIndex(์ฝœ๋ฐฑํ•จ์ˆ˜)' ๋ฉ”์„œ๋“œ๋ฅผ ์‚ฌ์šฉํ•ด ์กฐ๊ฑด์— ๋งž๋Š” index๋ฅผ ์•Œ์•„๋ƒ„
      2. element๋ฅผ ์—…๋ฐ์ดํŠธํ•˜๊ธฐ
        • ์ฐพ์€ index์— ๋Œ€ํ•œ element๋ฅผ ์ƒˆ๋กœ์šด ๊ฐ’์œผ๋กœ ๋Œ€์ฒด(replace)ํ•ด์•ผ ํ•จ
        • element๋ฅผ ๊ต์ฒดํ•˜๋Š” ์ด์œ ๋Š” ํ•ด๋‹น element์˜ ์œ„์น˜๊ฐ€ ๋ฐ”๋€Œ์ง€ ์•Š๊ธธ ๋ฐ”๋ผ๊ธฐ ๋•Œ๋ฌธ
        1. ๊ต์ฒดํ•  element์˜ ์•ž ๋ถ€๋ถ„์„ ์ƒˆ๋กœ์šด ๋ฐฐ์—ด๋กœ ์ƒ์„ฑํ•˜๊ธฐ
          • '.slice(์‹œ์ž‘์ธ๋ฑ์Šค, ๋์ธ๋ฑ์Šค)' ๋ฉ”์„œ๋“œ๋ฅผ ์‚ฌ์šฉํ•ด ์ƒˆ๋กœ์šด ๋ฐฐ์—ด ์ƒ์„ฑ
        2. ๊ต์ฒดํ•  element์˜ ๋’ท ๋ถ€๋ถ„์„ ์ƒˆ๋กœ์šด ๋ฐฐ์—ด๋กœ ์ƒ์„ฑํ•˜๊ธฐ
          • '.slice()' ๋ฉ”์„œ๋“œ์˜ ๋์ธ๋ฑ์Šค๋ฅผ ์ง€์ •ํ•˜์ง€ ์•Š์„ ์‹œ ๋๊นŒ์ง€ ์ž˜๋ผ์„œ ๋ฐ˜ํ™˜ํ•จ
        3. ๊ต์ฒด ํ›„ ์ƒˆ๋กœ์šด ๋ฐฐ์—ด๋กœ ์ƒ์„ฑํ•˜๊ธฐ
          • ๋ฐฐ์—ด์˜ ์Šคํ”„๋ ˆ๋“œ ์—ฐ์‚ฐ์ž(...)๋ฅผ ์ด์šฉํ•˜์—ฌ, ์•ž๋ถ€๋ถ„๊ณผ ๋’ท๋ถ€๋ถ„ ์‚ฌ์ด์— ์ƒˆ ์›์†Œ๋ฅผ ๋„ฃ์Œ
  • 23-09-05 : #6.16 ~ #7.1 / Recoil Selector + Recoil-Persist
    • Recoil - Selector
      • atom์˜ output์„ ๋ณ€ํ˜•์‹œํ‚ค๋Š” ๋„๊ตฌ (atom์˜ state ์ž์ฒด๋ฅผ ๋ฐ”๊พธ๋Š” ๊ฒƒ์ด ์•„๋‹ˆ๋ผ, ๊ทธ์˜ output์„ ๋ฐ”๊พธ๋Š” ๊ฒƒ)
      • ์„ ์–ธ๋ฒ• const ์…€๋ ‰ํ„ฐ๋ช… = selector({ ย ย key: ํ‚ค๊ฐ’, ย ย get: ({ get }) => { ย ย ย ย const ๋ณ€์ˆ˜๋ช… = get(์•„ํ†ฐ๋ช…); // atom์„ ๊ฐ€์ ธ์˜ค๋Š” ๋ฌธ (ํ•„์ˆ˜x) ย ย ย ย ...... ย ย ย ย return ๊ฐ’; ย ย }, });
        • get
          • ์ธ์ž๋กœ ๋ฐ›๋Š” ์˜ต์…˜ ์ค‘์˜ 'get'ํ•จ์ˆ˜๋ฅผ ์ด์šฉํ•ด atom์„ ๋ฐ›์•„์˜ฌ ์ˆ˜ ์žˆ์œผ๋ฉฐ, ์—ฌ๋Ÿฌ ๋ฒˆ ์‚ฌ์šฉํ•ด ์—ฌ๋Ÿฌ ๊ฐœ์˜ atom์„ ๊ฐ€์ ธ์˜ฌ ์ˆ˜ ์žˆ์Œ
          • returnํ•˜๋Š” ๊ฐ’์€ ํ•ด๋‹น selector์˜ value๊ฐ€ ๋จ
      • ์‚ฌ์šฉ๋ฒ• : const ๋ณ€์ˆ˜๋ช… = useRecoilValue(์…€๋ ‰ํ„ฐ๋ช…);
      • atom์ด ๋ณ€ํ•˜๋ฉด, selector๋„ ๋ณ€ํ•จ
    • Recoil - Selector์˜ 'set' ์†์„ฑ
      • selector์˜ 'set' ์†์„ฑ์„ ์‚ฌ์šฉํ•˜์—ฌ, selector์—์„œ atom์˜ state๋ฅผ ์ˆ˜์ •ํ•  ์ˆ˜ ์žˆ์Œ
      • ๊ธฐ๋ณธํ˜• ย ย set: ({ set }, ์ƒˆ๋กœ์šด๊ฐ’) => { ย ย ...... ย ย set(์•„ํ†ฐ๋ช…, ์ˆ˜์ •ํ• ๊ฐ’); // ์ƒˆ๋กœ์šด ๊ฐ’๊ณผ ์ˆ˜์ •ํ•  ๊ฐ’์€ ๊ฐ™์„ ํ•„์š” x }
        • ์—ฌ๋Ÿฌ ๊ฐœ์˜ atom์— ๋Œ€ํ•ด 'set()'ํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Œ
      • 'useRecoilState()'๋กœ selector๋ฅผ ๋ถˆ๋Ÿฌ์™€์„œ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Œ
        • ์ฒซ ๋ฒˆ์งธ ์š”์†Œ : get ํ”„๋กœํผํ‹ฐ๋กœ๋ถ€ํ„ฐ returnํ•œ ๊ฐ’
        • ๋‘ ๋ฒˆ์งธ ์š”์†Œ : set ํ”„๋กœํผํ‹ฐ๋กœ๋ฅผ ์‹คํ–‰์‹œํ‚ค๋Š” ํ•จ์ˆ˜
        • 'useRecoilState()'๋ฅผ atom๊ณผ selector ๋‘˜๋‹ค์—์„œ ์‚ฌ์šฉ ๊ฐ€๋Šฅ
    • enum
      • ์—ด๊ฑฐํ˜•(enumeration)์œผ๋กœ ์ •์˜ํ•˜๋Š” ๋ฐ ์‚ฌ์šฉํ•˜๋Š” ๋ฐ์ดํ„ฐ ํ˜•์‹
      • ๊ธฐ๋ณธํ˜•: enum ๋ณ€์ˆ˜๋ช… { ๊ฐ’1, ๊ฐ’2, ๊ฐ’3, ... }
        • ๋ณ€์ˆ˜๋ช…์€ ๋Œ€๋ฌธ์ž๋กœ ์‹œ์ž‘
        • ์ปดํ“จํ„ฐ๋Š” ์—ด๊ฑฐ ์ƒ์ˆ˜๋กœ ์‚ฌ์šฉํ•จ
          • ์—ด๊ฑฐ ์ƒ์ˆ˜๋Š” 0๋ถ€ํ„ฐ ์‹œ์ž‘ํ•˜์—ฌ ์ˆœ์„œ๋Œ€๋กœ 1์”ฉ ์ฆ๊ฐ€ํ•œ ๊ฐ’์„ ๊ฐ€์ง€๋ฉฐ, ์ˆœ์„œ๋ฅผ ๋”ฐ๋กœ ์ง€์ •ํ•˜์ง€ ์•Š๋Š” ํ•œ ์ž๋™์œผ๋กœ ํ• ๋‹น๋จ (์ˆ˜๋™ ํ• ๋‹น ๊ฐ€๋Šฅ, ์ˆซ์ž๋‚˜ ๋ฌธ์ž์—ด ๊ฐ€๋Šฅ)
          • ์ง์ ‘ ๊ฐ™์€ ๊ฐ’์œผ๋กœ ์ฃผ์–ด์„œ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Œ (ex. enum Categories { "TO_DO" = "TO_DO" })
      • ์‚ฌ์šฉ ์‹œ ํ”„๋กœํผํ‹ฐ ๋ฐฉ์‹์œผ๋กœ ์‚ฌ์šฉ (ex. Categories.TO_DO)
    • Recoil-Persist ํŒจํ‚ค์ง€
      • Recoil ์ƒํƒœ ๊ด€๋ฆฌ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์™€ Local Storage๋ฅผ ํ†ตํ•ฉํ•˜์—ฌ, Recoil ์ƒํƒœ๋ฅผ ์˜๊ตฌ์ ์œผ๋กœ ์ €์žฅํ•˜๊ณ  ๋ณต์›ํ•˜๋Š” ๋ฐ ๋„์›€์„ ์ฃผ๋Š” ํŒจํ‚ค์ง€
        • ๋ธŒ๋ผ์šฐ์ €์˜ Local Storage๋ฅผ ํ™œ์šฉํ•˜์—ฌ, Recoil ์ƒํƒœ๋ฅผ ์ง€์†์ ์œผ๋กœ ์œ ์ง€ํ•  ์ˆ˜ ์žˆ์Œ
      • ์„ค์น˜๋ฒ• : 'npm i recoil-persist'
      • ์„ค์ •๋ฒ•
        1. atom ํŒŒ์ผ์—์„œ 'recoilPersist' ๊ฐ์ฒด ์ƒ์„ฑํ•˜๊ธฐ
          • const { persistAtom } = recoilPersist();
            • 'recoilPersist()'์˜ ์˜ต์…˜
              • key : Local Storage์— ๋ฐ์ดํ„ฐ ์ €์žฅ ์‹œ ์‚ฌ์šฉ๋˜๋Š” key๋ช…
                • ๊ธฐ๋ณธ๊ฐ’ : "recoil-persist"
              • storage : ๋ฐ์ดํ„ฐ๋ฅผ ์ €์žฅํ•  ์ €์žฅ์†Œ ์„ค์ •
                • ๊ธฐ๋ณธ๊ฐ’ : localStorage
              • converter : ์ €์žฅ์†Œ์—์„œ ๊ฐ’์„ ์ง๋ ฌํ™”/์—ญ์ง๋ ฌํ™”ํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ๊ตฌ์„ฑ
                • ๊ธฐ๋ณธ๊ฐ’ : JSON
        2. Local Storage๋ฅผ ์‚ฌ์šฉํ•˜๊ณ ์ž ํ•˜๋Š” atom์— 'effect_UNSTABLE' ์†์„ฑ ํ• ๋‹นํ•˜๊ธฐ
          • 'effect_UNSTABLE: [persistAtom]' ์†์„ฑ๋งŒ ์ถ”๊ฐ€ํ•˜๋ฉด ๋จ
      • ์„ค์ •๋งŒ ํ•ด๋†“์œผ๋ฉด Local Storage์— ์ €์žฅ(set)๊ณผ ๋ถˆ๋Ÿฌ์˜ค๊ธฐ(get)๋ฅผ ์ž๋™์œผ๋กœ ์‹คํ–‰ํ•จ
  • 23-09-06 : #7.2 ~ #7.4 / React-Beautiful-Dnd(1)
    • react-beautiful-dnd ํŒจํ‚ค์ง€ (@hello-pangea/dnd)
      • ํ™”๋ฉด์—์„œ drag&drop์„ ํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•ด์ฃผ๋Š” ํŒจํ‚ค์ง€
      • ์„ค์น˜๋ฒ• : 'npm i @hello-pangea/dnd'
        • 'react-beautiful-dnd'๋Š” ์ข…์†์„ฑ ๋ฌธ์ œ๋•Œ๋ฌธ์— React 18๋ฒ„์ „์—์„œ ์ œ๋Œ€๋กœ ๋™์ž‘ํ•˜์ง€ ์•Š๊ณ , ํ•ด๋‹น ํŒจํ‚ค์ง€๊ฐ€ ๋” ์ด์ƒ ์—†๋Žƒ์ด๋ฏ€๋กœ ๋น„์ถ”์ฒœ
      • ์›น ํŽ˜์ด์ง€์—์„œ ์ž‘๋™์ด ๋˜์ง€ ์•Š์„ ์‹œ 'React.StrictMode'๋ฅผ ์ œ๊ฑฐํ•  ๊ฒƒ
    • <DragDropContext />
      • drag&drop์„ ๊ฐ€๋Šฅํ•˜๊ฒŒ ํ•˜๊ณ  ์‹ถ์€ ์•ฑ์˜ ํ•œ ๋ถ€๋ถ„(์˜์—ญ)
        • ์•ฑ ์ „์ฒด๊ฐ€ ์•„๋‹Œ ์‚ฌ์šฉ์ž๊ฐ€ drag&drop์„ ํ•  ํŠน์ • ์˜์—ญ์—๋งŒ ์ƒ์„ฑํ•˜๋„๋ก ํ•จ
      • ๊ธฐ๋ณธํ˜• : <DragDropContext onDragEnd={์ฝœ๋ฐฑํ•จ์ˆ˜}> ... </DragDropContext>
        • onDragEnd : [ํ•„์ˆ˜] ์‚ฌ์šฉ์ž๊ฐ€ drag๋ฅผ ๋๋‚ธ ์‹œ์ ์— ์‹คํ–‰ํ•˜๋Š” ์ฝœ๋ฐฑํ•จ์ˆ˜
          • ์ฝœ๋ฐฑํ•จ์ˆ˜์— ๋‚ด์šฉ์ด ์—†๋‹ค๋ฉด, drag&drop์ด ๋๋‚  ์‹œ ์›๋ž˜๋Œ€๋กœ ๋Œ์•„์˜ด
        • [ํ•„์ˆ˜] ํƒœ๊ทธ ์‚ฌ์ด์—๋Š” children(ํ•˜์œ„ ํƒœ๊ทธ)์ด ์žˆ์–ด์•ผ ํ•จ
    • <Droppable />
      • ์–ด๋–ค ๊ฒƒ์„ ๋“œ๋กญํ•  ์ˆ˜ ์žˆ๋Š” ์˜์—ญ(list)
      • ๊ธฐ๋ณธํ˜• : <Droppable droppableId="์ด๋ฆ„"> ... </Droppable>
        • droppableId : [ํ•„์ˆ˜] dropํ•  ์ˆ˜ ์žˆ๋Š” ์˜์—ญ์ด ์—ฌ๋Ÿฌ ๊ฐœ์ผ ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ
        • [ํ•„์ˆ˜] ํƒœ๊ทธ ์‚ฌ์ด์—๋Š” children(์ฝœ๋ฐฑํ•จ์ˆ˜ JSX)์ด ์žˆ์–ด์•ผ ํ•จ
          • ์ฝœ๋ฐฑํ•จ์ˆ˜์˜ ์ฒซ ๋ฒˆ์งธ ์ธ์ž๋กœ 'provided'๋ฅผ ๋ฐ›์Œ (์œ„์น˜๋งŒ ์ค‘์š”ํ•˜์ง€, ์ด๋ฆ„์€ ์•„๋ฌด๊ฑฐ๋‚˜ ๊ฐ€๋Šฅ)
          • ์ฝœ๋ฐฑํ•จ์ˆ˜์—์„œ ์‚ฌ์šฉ๋˜๋Š” JSX์— 'provided.droppableProps'์˜ ๋ชจ๋“  ํ”„๋กœํผํ‹ฐ์™€ 'ref'์†์„ฑ์œผ๋กœ 'provided.innerRef'๋ฅผ ์ฃผ์–ด์•ผ ํ•จ
          • ex. {(provided) => <ul ref={provided.innerRef} {...provided.droppableProps}> ... </ul>}
      • 'provided.placeholder' : </Droppable>์ด ๋๋‚  ๋•Œ ๋‘์–ด, drag&drop ์‹œ <Droppable>์˜ ์‚ฌ์ด์ฆˆ๊ฐ€ ์ด์ƒํ•˜๊ฒŒ ๋ณ€ํ•˜๋Š” ๊ฒƒ์„ ๋ง‰์Œ
        • <Droppable>์˜ ํ•˜์œ„ ์ฝœ๋ฐฑํ•จ์ˆ˜์—์„œ ์‚ฌ์šฉ๋œ JSX์˜ ๋‹ซํžŒ ํƒœ๊ทธ ๋ฐ”๋กœ ์•ž์—์„œ ์‚ฌ์šฉ
    • <Draggable />
      • ์‚ฌ์šฉ์ž๊ฐ€ dragํ•  ์ˆ˜ ์žˆ๋Š” ์˜์—ญ(list์— ์žˆ๋Š” item)
      • ๊ธฐ๋ณธํ˜• : <Draggable draggableId="์ด๋ฆ„" index={์ธ๋ฑ์Šค}> ...... </Draggable>
        • draggableId : [ํ•„์ˆ˜] dropํ•  ์ˆ˜ ์žˆ๋Š” ์˜์—ญ์ด ์—ฌ๋Ÿฌ ๊ฐœ์ผ ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ
          • 'key'์†์„ฑ ์‚ฌ์šฉ ์‹œ 'draggableId'์˜ ์†์„ฑ๊ฐ’๊ณผ ๊ฐ™์•„์•ผ ํ•จ (drag&drop ํ•  ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ)
        • index : [ํ•„์ˆ˜] sorting์„ ์œ„ํ•œ ํ”„๋กœํผํ‹ฐ
        • [ํ•„์ˆ˜] ํƒœ๊ทธ ์‚ฌ์ด์—๋Š” children(์ฝœ๋ฐฑํ•จ์ˆ˜ JSX)์ด ์žˆ์–ด์•ผ ํ•จ
          • ์ฝœ๋ฐฑํ•จ์ˆ˜์˜ ์ฒซ ๋ฒˆ์งธ ์ธ์ž๋กœ 'provided'๋ฅผ ๋ฐ›์Œ (์œ„์น˜๋งŒ ์ค‘์š”ํ•˜์ง€, ์ด๋ฆ„์€ ์•„๋ฌด๊ฑฐ๋‚˜ ๊ฐ€๋Šฅ)
          • provided.draggableProps : ํ•ด๋‹น element์˜ drag ๊ธฐ๋Šฅ
          • provided.dragHandleProps : dragํ•˜๊ธฐ ์œ„ํ•ด ์žก์„ ์ˆ˜ ์žˆ๋Š” ์˜์—ญ
            • ํ•ด๋‹น ํ”„๋กœํผํ‹ฐ๋ฅผ ์ค€ element๋ฅผ drag ํ•ด์•ผํ•จ
          • ์ฝœ๋ฐฑํ•จ์ˆ˜์—์„œ ์‚ฌ์šฉ๋˜๋Š” JSX์— 'provided.draggableProps'์˜ ๋ชจ๋“  ํ”„๋กœํผํ‹ฐ์™€ 'provided.dragHandleProps'์˜ ๋ชจ๋“  ํ”„๋กœํผํ‹ฐ์™€ 'ref'์†์„ฑ์œผ๋กœ 'provided.innerRef'๋ฅผ ์ฃผ์–ด์•ผ ํ•จ
          • ex. {(provided) => <li ref={provided.innerRef} {...provided.draggableProps} {...provided.dragHandleProps}> ...... </li>}
  • 23-09-07 : #7.5 ~ #7.11 / React-Beautiful-Dnd(2)
    • <DragDropContext> - 'onDragEnd'
      • 'onDragEnd' ํ”„๋กœํผํ‹ฐ๋Š” drag&drop์ด ๋๋‚  ๋•Œ ์‹คํ–‰ํ•˜๋Š” ํ•จ์ˆ˜
      • ์–ด๋–ค ์ผ์ด ์ผ์–ด๋‚ฌ๋Š”์ง€์— ๋Œ€ํ•œ ์ •๋ณด๋ฅผ ๋‹ด๊ณ ์žˆ๋Š” argument๋ฅผ ์ œ๊ณตํ•จ
        • 'onDragEnd'์˜ ์ธ์ž์˜ ํƒ€์ž…์€ 'DropResult' (ํƒ€์ž… ๋ฌธ์„œ ์ฐธ์กฐ)
        • draggableId : drag&drop์„ ํ•œ element๋ฅผ ์•Œ๋ ค์คŒ
        • destination : ๋ชฉ์ ์ง€์˜ ์ •๋ณด { droppableId, index }
        • source : ์ถœ๋ฐœ์ง€์˜ ์ •๋ณด { droppableId, index }
      • drag&drop์„ ํ•œ element๋ฅผ ์ €์žฅํ•œ ๋ฐฐ์—ด์—์„œ๋„ ๋˜‘๊ฐ™์ด ๋งŒ๋“ค์–ด์ฃผ์–ด์•ผ ํ•จ
        1. ๋ฐฐ์—ด์—์„œ dragํ•œ element๋ฅผ ์‚ญ์ œํ•˜๊ธฐ
          • 'source.index'๋ฅผ ์ฐธ์กฐํ•ด ์‚ญ์ œ
          • ๋ฐฐ์—ด.splice(์‹œ์ž‘์ธ๋ฑ์Šค, ์‚ญ์ œํ• ๊ฐฏ์ˆ˜) : ํ•ด๋‹น item์„ ๋ฐฐ์—ด์—์„œ ์‚ญ์ œํ•˜๋Š” ๋ฉ”์„œ๋“œ
            • ์›๋ณธ ๋ฐฐ์—ด์ด ๋ฐ”๋€Œ๋Š” mutation์ด ์ผ์–ด๋‚˜๋ฏ€๋กœ, ๋จผ์ € ์›๋ณธ์„ ๋ณต์‚ฌํ•œ ํ›„ ์‚ฌ์šฉํ•ด์•ผ ํ•จ
            • ๋ฐฐ์—ด ๋ณต์‚ฌ ์‹œ ์Šคํ”„๋ ˆ๋“œ ์—ฐ์‚ฐ์ž(...)๋ฅผ ์‚ฌ์šฉํ•œ '[...๋ฐฐ์—ด๋ช…]' ๋ฐฉ์‹์œผ๋กœ ๋ณต์‚ฌํ•ด์•ผ ํ•จ
              • ๋ฐฐ์—ด์€ ๊ทธ๋ƒฅ ๋ณต์‚ฌ ์‹œ ์ฃผ์†Œ๊ฐ’๋งŒ ์—ฐ๊ฒฐ๋˜๊ธฐ ๋•Œ๋ฌธ
        2. ์‚ญ์ œํ•œ element๋ฅผ ๋ฐฐ์—ด์—์„œ dropํ•œ ์œ„์น˜์— ์ƒ์„ฑํ•˜๊ธฐ
          • 'destination.index'์™€ 'draggableId'๋ฅผ ์ฐธ์กฐํ•ด ์ƒ์„ฑ
          • ๋ฐฐ์—ด.splice(์‹œ์ž‘์ธ๋ฑ์Šค, ์‚ญ์ œํ• ๊ฐฏ์ˆ˜, ์•„์ดํ…œ) : ์‚ญ์ œํ•  ๊ฐฏ์ˆ˜๋ฅผ 0์œผ๋กœ ํ•˜๊ณ  ์•„์ดํ…œ ๋งค๊ฐœ๋ณ€์ˆ˜๋ฅผ ๋„ฃ์–ด์ฃผ๋ฉด, ๋ฐฐ์—ด์˜ ํ•ด๋‹น ์ธ๋ฑ์Šค์— ์•„์ดํ…œ์„ ์ถ”๊ฐ€ํ•  ์ˆ˜ ์žˆ์Œ
          • 'destination'์ด ์—†์„ ์ˆ˜๋„ ์žˆ์Œ (๊ฐ™์€ ์ž๋ฆฌ์— drag&drop์„ ํ•  ์ˆ˜๋„ ์žˆ๊ธฐ ๋•Œ๋ฌธ)
    • ๋ฌธ์ œ ๋ฐœ์ƒ : drag&drop ์‹œ ๊ฐ€๋” content๊ฐ€ ๋–จ๋ฆฌ๋Š” ํ˜„์ƒ (์ตœ์ ํ™” ๋ฌธ์ œ)
      • ์ด์œ  : ๋ถ€๋ชจ component์˜ state๊ฐ€ ๋ณ€ํ•˜๋ฉด, ์ž์‹ component๋“ค๊นŒ์ง€ ์ „๋ถ€ re-rendering๋˜๊ธฐ ๋•Œ๋ฌธ (React์˜ ๊ธฐ๋ณธ ๋™์ž‘ ๋ฐฉ์‹)
        • dragํ•˜๋Š” component ์ด์™ธ์—๋„, ํ˜•์ œ component ๋“ฑ ์ „๋ถ€๊ฐ€ re-rendering ๋จ
        • console.log()๋กœ ํ™•์ธ ๊ฐ€๋Šฅ
      • ํ•ด๊ฒฐ : 'React.memo()'๋ฅผ ์‚ฌ์šฉํ•ด ํ•ด๊ฒฐ
        • ํ•ด๋‹น component์˜ prop์ด ๋ณ€ํ•˜์ง€ ์•Š์•˜๋‹ค๋ฉด, re-renderingํ•˜์ง€ ์•Š๋„๋ก ํ•จ
        • 'export default React.memo(์ปดํฌ๋„ŒํŠธ๋ช…);'์„ ์‚ฌ์šฉ
    • ๋‹ค์ˆ˜์˜ ๋ณด๋“œ(<Droppable>) ์‚ฌ์šฉํ•˜๊ธฐ
      • ์ค€๋น„ ๊ณผ์ •
        1. ๋‹ค์ˆ˜์˜ ๋ณด๋“œ๋ฅผ ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•ด, atomState๋ฅผ ์—ฌ๋Ÿฌ ๊ฐœ์˜ Array๋ฅผ ๊ฐ€์ง€๋Š” Object๋กœ ์‚ฌ์šฉํ•˜๊ธฐ
        2. '.map()'์„ ์‚ฌ์šฉํ•ด ์—ฌ๋Ÿฌ ๊ฐœ์˜ ๋ณด๋“œ๋ฅผ renderingํ•˜๊ธฐ
          • 'Object.keys(๊ฐ์ฒด๋ช…)'์œผ๋กœ ํ•ด๋‹น ๊ฐ์ฒด์˜ key๋ช…๋“ค์„ ๋ฐฐ์—ด๋กœ ๋ฝ‘์•„๋‚ผ ์ˆ˜ ์žˆ์Œ
            • 'Object.keys(๊ฐ์ฒด๋ช…).map(ํ‚ค๋ช… => ๊ฐ์ฒด๋ช…[ํ‚ค๋ช…])'์„ ์‚ฌ์šฉํ•ด ๊ฐ key์˜ ๊ฐ’๋“ค์„ ๋ฝ‘์•„๋‚ผ ์ˆ˜ ์žˆ์Œ
          • ์‚ฌ์šฉ์ž๊ฐ€ ์—ฌ๋Ÿฌ ๊ฐœ์˜ ๋ณด๋“œ๋ฅผ ์ƒ์„ฑ/์‚ญ์ œ ํ•  ์ˆ˜ ์žˆ์œผ๋‹ˆ, interface๋ฅผ ์„ค์ •ํ•ด์ค˜์•ผ ํ•จ
            • ex. interface IToDoState { [key: string]: string[]; }
      • drag&drop์„ ์‚ฌ์šฉํ•˜๋ ค๋ฉด, ํ˜„์žฌ ์œ„์น˜์˜ Array์—์„œ ์ œ๊ฑฐํ•œ ํ›„ ์ƒˆ๋กœ์šด ์œ„์น˜์˜ Array์— ๋ถ™์—ฌ๋†“๊ธฐ
        • 'source'์™€ 'destination'์„ ์ฐธ์กฐ ๊ฐ€๋Šฅ
        1. source์˜ ๋ณด๋“œ์™€ destination์˜ ๋ณด๋“œ๊ฐ€ ๊ฐ™์€์ง€ ์ฒดํฌํ•˜๊ธฐ
          • ๊ฐ๊ฐ '.droppableId'๋ฅผ ํ†ตํ•ด ์ฐธ์กฐ ๊ฐ€๋Šฅ
        2. ๊ฐ™์€ ๋ณด๋“œ์—์„œ ์ด๋™์ด ์ผ์–ด๋‚  ์‹œ
          1. ์ˆ˜์ •์ด ์ผ์–ด๋‚œ ๋ณด๋“œ๋งŒ ๋ณต์‚ฌํ•˜๊ธฐ
          2. ๋ณต์‚ฌํ•œ ๋ณด๋“œ๋ฅผ ์ˆ˜์ •ํ•œ ํ›„, ๋‹ค๋ฅธ ๋ณด๋“œ๋“ค ์˜†์— ๋†“๊ธฐ
        3. ๋‹ค๋ฅธ ๋ณด๋“œ๋กœ ์ด๋™์ด ์ผ์–ด๋‚  ์‹œ
          1. ์ถœ๋ฐœ์ง€ ๋ณด๋“œ์™€ ๋„์ฐฉ์ง€ ๋ณด๋“œ๋ฅผ ๋ณต์‚ฌํ•˜๊ธฐ
          2. ๋ณต์‚ฌํ•œ ๋ณด๋“œ๋“ค์„ ์ˆ˜์ •ํ•œ ํ›„, ๋‹ค๋ฅธ ๋ณด๋“œ๋“ค ์˜†์— ๋†“๊ธฐ
        • ๋‹ค๋ฅธ ๋ณด๋“œ๋“ค ์˜†์— ๋†“๊ธฐ ์œ„ํ•ด ์Šคํ”„๋ ˆ๋“œ์—ฐ์‚ฐ์ž(...)์™€ computed property name์„ ์ด์šฉํ•ด์•ผ ํ•˜๋ฉฐ(ES6), ์ „์ฒด ๊ฐ์ฒด๊ฐ€ ๋จผ์ € ์‚ฌ์šฉ๋˜์–ด์•ผ ํ•จ
          • ex. return { ...allBoards, [source.droppableId]: boardCopy }
    • ๋ฌธ์ œ ๋ฐœ์ƒ : item์„ ๊ฐ€์ง€๊ณ  ์žˆ์ง€ ์•Š๋Š” ๋ณด๋“œ์—๋Š” ํ•ด๋‹น ๋ณด๋“œ ๋งจ ์œ„๋กœ ์ด๋™ํ•ด์•ผ์ง€๋งŒ item์„ ๋ฐ›์„ ์ˆ˜ ์žˆ๋Š” ๋ถˆํŽธํ•จ
      • CSS๋กœ ๋ฐ›๋Š” ๋ถ€๋ถ„(<Droppable>์˜ ํ•˜์œ„ element)์˜ ์˜์—ญ์„ ๋ถ€๋ชจ element์— ๊ฐ€๋“ ์ฐจ๊ฒŒ๋” ๋งŒ๋“ค๊ธฐ
      • ํ•ด๊ฒฐ ๋ฐฉ๋ฒ•
        1. ๋ถ€๋ชจ element์— 'display: flex;' CSS๋ฅผ ๋ถ€์—ฌํ•˜๊ธฐ
        2. ์ž์‹ element์— 'flex-grow: 1;' CSS๋ฅผ ๋ถ€์—ฌํ•˜๊ธฐ
        • ์ž์‹ element์˜ ์˜์—ญ์ด ๋ถ€๋ชจ element์— ๊ฐ€๋“ ์ฐจ๊ฒŒ๋” ๋งŒ๋“ฆ
    • <Droppable>, <Draggable> - snapshot
      • <Droppable> ๋˜๋Š” <Draggable>์˜ children์œผ๋กœ ์‚ฌ์šฉ๋˜๋Š” ์ฝœ๋ฐฑํ•จ์ˆ˜์˜ ๋‘ ๋ฒˆ์งธ ์ธ์ž๋กœ 'snapshot'์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Œ
        • ๋‘ ๋ฒˆ์งธ ์ž๋ฆฌ๊ฐ€ ์ค‘์š”ํ•จ, ์ด๋ฆ„์€ ์•„๋ฌด๊ฑฐ๋‚˜ ์ƒ๊ด€์—†์Œ
      • 'snapshot'์˜ ํ”„๋กœํผํ‹ฐ๋Š” ํ˜•์‹ ์ •์˜ ํŒŒ์ผ์—์„œ ํ™•์ธ ๊ฐ€๋Šฅ
        • isDraggingOver : ๋ณด๋“œ๋กœ ๋“ค์–ด์˜ฌ ๋•Œ์˜ dragging์— ๋Œ€ํ•œ boolean๊ฐ’์„ ๋ฐ›์Œ
          • ์‚ฌ์šฉ์ž๊ฐ€ ๋ณด๋“œ ์œ„๋กœ dragํ•ด์„œ ๋“ค์–ด์˜ค๊ณ  ์žˆ๋Š”์ง€ ์•Œ๋ ค์คŒ
        • draggingFormThisWith : ์‚ฌ์šฉ์ž๊ฐ€ ํ•ด๋‹น ๋ณด๋“œ๋กœ๋ถ€ํ„ฐ drag๋ฅผ ์‹œ์ž‘ํ–ˆ๋Š”์ง€๋„ ์•Œ๋ ค์คŒ
          • ์‚ฌ์šฉ์ž๊ฐ€ ์–ด๋–ค ๋ณด๋“œ๋ฅผ ๋– ๋‚œ๋‹ค๋ฉด, ๊ทธ ๋ณด๋“œ๋กœ๋ถ€ํ„ฐ drag๋ฅผ ์‹œ์ž‘ํ–ˆ๋‹ค๋Š” ๋œป
          • DraggableId | undefined
          • 'Boolean(draggingFormThisWith)'๋กœ ์‚ฌ์šฉ ์‹œ dragํ•˜์—ฌ ํ•ด๋‹น ๋ณด๋“œ๋ฅผ ๋– ๋‚˜๋ฉด true
      • ์‚ฌ์šฉ๋ฒ• : <Droppable>์˜ ์ฝœ๋ฐฑํ•จ์ˆ˜ JSX element์—์„œ ํ”„๋กœํผํ‹ฐ๋ฅผ ๋ถ€์—ฌํ•˜์—ฌ ์‚ฌ์šฉ
        • element๋Š” snapshot์˜ ํ”„๋กœํผํ‹ฐ๋ฅผ ๋ชจ๋ฅด๊ธฐ ๋•Œ๋ฌธ์—, ํ˜•์‹ ์ •์˜๋ฅผ ํ•ด์ฃผ์–ด์•ผ ํ•จ
        • ํ”„๋กœํผํ‹ฐ๋ฅผ ์ด์šฉํ•ด styled-components๋กœ CSS ์ ์šฉ ๊ฐ€๋Šฅ
  • 23-09-08 : #7.12 ~ #7.16 / React-Beautiful-Dnd(3) + Code Challenge(1)
    • React - ref ์†์„ฑ
      • React.js component๋ฅผ ํ†ตํ•ด HTML element๋ฅผ ๊ฐ€์ ธ์™€์„œ ๊ทธ๊ฑธ ๋ณ€ํ˜•์‹œํ‚ฌ ์ˆ˜ ์žˆ๋„๋ก ํ•ด์คŒ
        • aka. vanilla JS์˜ document.getElementById()
      • ๊ธฐ๋ณธํ˜• const ๋ณ€์ˆ˜๋ช… = useRef<์ œ๋„ค๋ฆญ>(null); <ํƒœ๊ทธ๋ช… ref={๋ณ€์ˆ˜๋ช…} />
        • ๋ณดํ†ต 'useRef()'์˜ ์ธ์ž๋กœ null๊ฐ’์„ ์‚ฌ์šฉํ•จ (์ฐธ์กฐํ•  element๋ฅผ ์ดˆ๊ธฐํ™”ํ•œ ํ›„ ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•จ)
    • To-Do์˜ ํƒ€์ž… ๊ต์ฒด
      • 'string[]'์—์„œ '{ id:number, text: string }[]'์ธ ํƒ€์ž…์œผ๋กœ ๊ต์ฒด
      • ๋ฌธ์ œ ๋ฐœ์ƒ : 'onDragEnd'์—์„œ 'draggableId'๋ฅผ ์ฐธ์กฐํ•ด ์žฌ๋ฐฐ์—ด ํ•œ ๊ฒƒ์„ ๋ฐ”๊พธ์–ด์ค˜์•ผ ํ•จ
        • ๊ธฐ์กด์˜ string[] ํƒ€์ž…์—์„œ๋Š” draggableId = item ์ด์–ด์„œ ์‰ฌ์› ์Œ
        • ์ง€๊ธˆ์˜ draggableId๋Š” stringํƒ€์ž…์˜ id ํ”„๋กœํผํ‹ฐ ๊ฐ’์ž„
      • ํ•ด๊ฒฐ ๋ฐฉ๋ฒ• : '.index' ํ”„๋กœํผํ‹ฐ๋ฅผ ์ด์šฉํ•ด์„œ item์„ ์ฐพ๊ธฐ
        • 'source.index'๋ฅผ ํ†ตํ•ด ํƒ€๊ฒŸ(Object)์„ ์ฐพ์€ ํ›„ ์‚ฌ์šฉ
  • 23-09-09 ~ 10 : Code Challenge(2)
  • 23-09-12 : #8.0 ~ #8.6 / Animations(1)
    • Framer-Motion ํŒจํ‚ค์ง€
      • ์• ๋‹ˆ๋ฉ”์ด์…˜์„ ๋งŒ๋“ค ์ˆ˜ ์žˆ๋Š” React.js์šฉ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ
        • CSS transition ์ฝ”๋“œ ์—†์ด ์ž‘๋™ํ•˜๋Š” ์• ๋‹ˆ๋ฉ”์ด์…˜
      • ์„ค์น˜๋ฒ• : 'npm i framer-motion'
      • ์„ค์ •๋ฒ• : 'import { motion } from "framer-motion";'
      • ๊ทœ์น™ : 'motion'์˜ ํ”„๋กœํผํ‹ฐ๋ฅผ HTMLํƒœ๊ทธ๋ช…์œผ๋กœ ์‚ฌ์šฉํ•ด์•ผ์ง€ ์• ๋‹ˆ๋ฉ”์ด์…˜์„ ๋งŒ๋“ค ์ˆ˜ ์žˆ์Œ
        • ๊ธฐ๋ณธํ˜• : <motion.HTMLํƒœ๊ทธ๋ช…>
      • 'styled-components'์—์„œ motion ์• ๋‹ˆ๋ฉ”์ด์…˜ ํƒœ๊ทธ ์ƒ์„ฑ๋ฒ•
        • ๊ธฐ๋ณธํ˜• : const ์ปดํฌ๋„ŒํŠธ๋ช… = styled(ํƒœ๊ทธ๋ช…)` ... `;
    • motion์˜ props
      • ๊ธฐ๋ณธ์ ์œผ๋กœ 'style'ํ”„๋กœํผํ‹ฐ์ฒ˜๋Ÿผ ์—ฐ์†ํ•˜๋Š” 2๊ฐœ์˜ ์ค‘๊ด„ํ˜ธ๋ฅผ ์‚ฌ์šฉ ({{, }})
      • initial : element์˜ ์ดˆ๊ธฐ ์ƒํƒœ๋ฅผ ๋‚˜ํƒ€๋ƒ„
      • animate : element์˜ ์ตœ์ข… ์ƒํƒœ๋ฅผ ๋‚˜ํƒ€๋ƒ„
      • transition : ํŠธ๋žœ์ง€์…˜ ํ”„๋กœํผํ‹ฐ
        • delay : n์ดˆ ํ›„์— ์• ๋‹ˆ๋ฉ”์ด์…˜ ๋ฐœ์ƒ [seconds]
        • duration : n์ดˆ ๋™์•ˆ ์• ๋‹ˆ๋ฉ”์ด์…˜ ๋ฐœ์ƒ [seconds]
    • ์• ๋‹ˆ๋ฉ”์ด์…˜ ๋งŒ๋“ค๊ธฐ
      • ๊ธฐ๋ณธ๊ฐ’์œผ๋กœ ์‚ด์ง ํŠ•๊ธฐ๋Š” ๋“ฏํ•œ ๋А๋‚Œ์œผ๋กœ 'type: "spring"'์ด ์ ์šฉ๋˜์–ด ์žˆ์Œ
        • stiffness : [number] ๊ฒฝ์ง๋จ
        • damping : [number] ๋ฐ˜๋™๋ ฅ
        • bounce : ํŠ•๊ธฐ๋Š” ์ •๋„
        • mass : ๋ฌผ์ฒด์˜ ์งˆ๋Ÿ‰
      • 'type: "tween"' : ์„ ํ˜•์ (linear)
    • Variants
      • ์• ๋‹ˆ๋ฉ”์ด์…˜ ์„ค์ •์„ ๋ถ„๋ฆฌ๋œ Object๋กœ ์˜ฎ๊ฒจ์„œ ์‚ฌ์šฉํ•˜๋Š” ๋ฐฉ๋ฒ•
      • ์ดˆ๊ธฐ ์ƒํƒœ์™€ ์ตœ์ข… ์ƒํƒœ๋ฅผ ๋ช…์‹œํ•ด์•ผ ํ•จ
        • ์ด๋ฆ„์€ ์•„๋ฌด๊ฑฐ๋‚˜ ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•˜์ง€๋งŒ, ์‚ฌ์šฉ ์‹œ ์ด๋ฆ„์ด ๊ฐ™์•„์•ผ ํ•จ
        • ์ตœ์ข… ์ƒํƒœ์˜ ์˜ต์…˜์œผ๋กœ 'transition'์„ ๋„ฃ์–ด์ค„ ์ˆ˜ ์žˆ์Œ
        • Variants์— ํ”„๋กœํผํ‹ฐ๋ฅผ ๋” ์ถ”๊ฐ€ํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ, :hover ๋“ฑ์— ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Œ
      • ๊ธฐ๋ณธํ˜• const ๋ณ€์ˆ˜๋ช… = { ย ย ์ดˆ๊ธฐ์ƒํƒœ๋ช… : { ... }, ย ย ์ตœ์ข…์ƒํƒœ๋ช… : {}, } <ํƒœ๊ทธ๋ช… variants={๋ณ€์ˆ˜๋ช…} initial="์ดˆ๊ธฐ์ƒํƒœ๋ช…" animate="์ตœ์ข…์ƒํƒœ๋ช…">
    • Variants - ์ž์‹ ์ปดํฌ๋„ŒํŠธ
      • ๋ถ€๋ชจ ์ปดํฌ๋„ŒํŠธ๊ฐ€ variants, initial, animate๋ฅผ ๊ฐ–๊ณ  ์žˆ์„ ๋•Œ ๊ธฐ๋ณธ๊ฐ’์œผ๋กœ ์ž์‹ ์ปดํฌ๋„ŒํŠธ์—๋„ ์ ์šฉ๋จ
        • ์ž๋™์œผ๋กœ ๋ถ€๋ชจ์˜ initial, animate์˜ ๊ฐ’์„ ์ƒ์†๋ฐ›์Œ
      • ์ž์‹ ์ปดํฌ๋„ŒํŠธ์— ์ƒˆ๋กœ์šด variants ์ ์šฉ ์‹œ variants๋งŒ ์ ์–ด์ฃผ๋ฉด ๋จ
        • ๋‹จ, ์ƒํƒœ๋ช…์€ ๋ถ€๋ชจ variants์™€ ๊ฐ™์€ ์ด๋ฆ„์„ ์‚ฌ์šฉํ•ด์•ผ ํ•จ
          • ์ž๋™์œผ๋กœ initial, animate๋ฅผ ๋ณต๋ถ™ํ•˜๊ธฐ ๋•Œ๋ฌธ
      • ๋ถ€๋ชจ ์ปดํฌ๋„ŒํŠธ์—์„œ ์ž์‹ ์ปดํฌ๋„ŒํŠธ์˜ 'delay'๋ฅผ ์กฐ์ ˆ ๊ฐ€๋Šฅ
        • delayChildren : ์ž์‹ ์ปดํฌ๋„ŒํŠธ๋“ค์˜ delay ์‹œ๊ฐ„ [seconds]
        • staggerChildren : ๊ฐ๊ฐ์˜ ์ž์‹ ์ปดํฌ๋„ŒํŠธ๋“ค์˜ delay ์‹œ์ฐจ [seconds]
    • event์— ๋”ฐ๋ฅธ animation
      • 'while์ด๋ฒคํŠธ๋ช…' ์†์„ฑ์„ ์‚ฌ์šฉ
        • { whileHover, whileTap, whileDrag, whileFocus, whileInView }
      • variants์—์„œ ์ƒํƒœ๋ช… ํ‚ค-๊ฐ’์„ ์‚ฌ์šฉ ๊ฐ€๋Šฅ
    • Dragging (๋“œ๋ž˜๊น…)
      • ์‚ฌ์šฉ๋ฒ• : ์ปดํฌ๋„ŒํŠธ์— 'drag'์†์„ฑ์„ ๋ถ€์—ฌํ•˜๋ฉด ๋จ
        • 'drag="x"' : x์ถ•์œผ๋กœ๋งŒ drag ๊ฐ€๋Šฅ
        • 'drag="y"' : y์ถ•์œผ๋กœ๋งŒ drag ๊ฐ€๋Šฅ
      • whileDrag : dragํ•˜๋Š” ๋™์•ˆ ๋‚˜ํƒ€๋‚˜๋Š” animation ์†์„ฑ
        • ์ƒ‰์„ ์‚ฌ์šฉํ•  ๋•Œ number๊ฐ’(rgb, hex ๋“ฑ)์„ ์‚ฌ์šฉํ•ด์•ผ์ง€ ์ž๋™์œผ๋กœ transition์ด ์ž‘๋™ํ•จ
          • ๊ทธ๋ ‡์ง€ ์•Š์œผ๋ฉด(string ๋“ฑ), ์ฆ‰๊ฐ์ ์œผ๋กœ ์ƒ‰์ด ๋ณ€ํ•จ
      • dragConstraints : drag๊ฐ€ ํ—ˆ์šฉ๋  ์ˆ˜ ์žˆ๋Š” ์˜์—ญ
        • { top, bottom, left, right }
        • ์ œํ•œ๋œ ์˜์—ญ์„ ๋„˜์–ด์„œ๋ฉด, ์˜์—ญ ๋‚ด๋กœ ๋˜๋Œ์•„๊ฐ
      • dragSnapToOrigin : drag๊ฐ€ ๋๋‚˜๋ฉด ์ฒ˜์Œ ์œ„์น˜๋กœ ๋˜๋Œ์•„๊ฐ€๋Š” ์†์„ฑ
      • dragElastic : drag ์‹œ์˜ ๋‹น๊ธฐ๋Š” ํž˜
        • 0~1 ์‚ฌ์ด์˜ ๊ฐ’์„ ๊ฐ€์ง (๊ธฐ๋ณธ๊ฐ’ 0.5)
        • 0 : drag์š”์†Œ๊ฐ€ ์ œํ•œ๋œ ์˜์—ญ ๋ฐ–์œผ๋กœ ๋‚˜๊ฐˆ ์ˆ˜ ์—†์Œ
        • 1 : drag์š”์†Œ์™€ ๋งˆ์šฐ์Šค ์ปค์„œ๊ฐ€ ๊ฐ™์€ ์œ„์น˜๋กœ dragํ•จ
      • ์ œํ•œ๋œ ์˜์—ญ ๋‚ด์—์„œ๋งŒ dragging์„ ํ—ˆ์šฉ์‹œํ‚ค๋Š” ๋ฐฉ๋ฒ•
        1. ์ œํ•œ๋œ ์˜์—ญ์„ ๊ฐ€์ง€๋Š” div ์ปดํฌ๋„ŒํŠธ ๋‚ด์— dragํ•  ์ˆ˜ ์žˆ๋Š” ์ปดํฌ๋„ŒํŠธ ์ƒ์„ฑํ•˜๊ธฐ
        2. ์ œํ•œ๋œ ์˜์—ญ(๋ถ€๋ชจ) ์ปดํฌ๋„ŒํŠธ์— CSS 'overflow: hidden' ์†์„ฑ ๋ถ€์—ฌํ•˜๊ธฐ
          • 'overflow: hidden' : ํ•˜์œ„ ์š”์†Œ๊ฐ€ ๋ถ€๋ชจ ์š”์†Œ์˜ ๋‚ด์—์„œ๋งŒ ๋ณด์ด๋„๋ก ํ•จ (์ดˆ๊ณผ๋œ ๋ถ€๋ถ„์€ ๋ณด์ด์ง€ ์•Š์Œ)
        3. ์ œํ•œ๋œ์˜์—ญ ๋‚ด์—์„œ๋งŒ dragํ•  ์ˆ˜ ์žˆ๋„๋ก ์ œ์•ฝ์„ ๋„ฃ๊ธฐ
          1. ์ˆ˜ํ•™์  ๋ฐฉ๋ฒ•
            • ex. ์ œํ•œ์˜์—ญ=600x600 / ๋“œ๋ž˜๊ทธ์š”์†Œ=200x200 dragConstraints={{ top: -200, bottom: 200, left: -200, right: 200 }}
          2. 'ref' ์†์„ฑ์„ ์ด์šฉํ•˜๋Š” ๋ฐฉ๋ฒ•
            • ์ œํ•œ๋œ ์˜์—ญ์˜ 'ref'๋ฅผ ์„ค์ •ํ•œ ํ›„, ๋“œ๋ž˜๊น… ์š”์†Œ์˜ 'dragConstraints'์— ์ œํ•œ๋œ ์˜์—ญ์˜ ref๋ฅผ ํ• ๋‹น
            • ๊ธฐ๋ณธํ˜• : const ๋ณ€์ˆ˜๋ช… = useRef<์ œ๋„ค๋ฆญ>(null);
  • 23-09-14 : #8.7 ~ #8.13 / Animations(2)
    • Motion Value
      • ์• ๋‹ˆ๋ฉ”์ด์…˜ ๋‚ด์˜ ์ˆ˜์น˜๋ฅผ trackingํ•  ๋•Œ ํ•„์š”ํ•œ ๋ณ€์ˆ˜
        • dragging์„ ์™ผ์ชฝ/์˜ค๋ฅธ์ชฝ์— ๋”ฐ๋ผ ๋ฐฐ๊ฒฝ์ƒ‰์„ ๋ฐ”๊พธ๋Š” ๋“ฑ
      • Motion Value๊ฐ€ ๋ฐ”๋€Œ์–ด๋„, ์ปดํฌ๋„ŒํŠธ๊ฐ€ re-renderingํ•˜์ง€ ์•Š์Œ (state๊ฐ’์ด ์•„๋‹ˆ๊ธฐ ๋•Œ๋ฌธ)
      • ์‚ฌ์šฉ๋ฒ• const ๋ณ€์ˆ˜๋ช… = useMotionValue(์ดˆ๊ธฐ๊ฐ’); <ํƒœ๊ทธ๋ช… style={{ ์†์„ฑ: ๋ณ€์ˆ˜๋ช… }} />
        • ๋ณ€์ˆ˜๋ช….get() : ํ˜„์žฌ ๊ฐ’์„ ๋ถˆ๋Ÿฌ์˜ค๋Š” ๋ฉ”์„œ๋“œ
        • ๋ณ€์ˆ˜๋ช….set() : ํ•ด๋‹น ๊ฐ’์œผ๋กœ ์ฒ˜๋ฆฌํ•˜๋Š” ๋ฉ”์„œ๋“œ
        • ex. const x = useMotionValue(); <button onClick={() => x.set(200)}>Click me</button> <Box style={{ x }} drag="x" />
    • useMotionValueEvent()
      • 'motion value'๊ฐ’์„ ์•Œ์•„๋ณด๊ธฐ ์œ„ํ•ด ์‚ฌ์šฉํ•˜๋Š” ๋ฉ”์„œ๋“œ
      • ๊ธฐ๋ณธํ˜• : useMotionValueEvent(๋ณ€์ˆ˜๋ช…, ์ด๋ฒคํŠธ๋ช…, ์ฝœ๋ฐฑํ•จ์ˆ˜);
        • ์ด๋ฒคํŠธ๋ช… ์ค‘ "change"๋Š” ์ฝœ๋ฐฑํ•จ์ˆ˜์˜ ์ธ์ž๋กœ 'latest'๊ฐ’(= .get()) ์ œ๊ณต
    • useTransform()
      • 'motion value' ์ž…๋ ฅ ๋ฒ”์œ„๋ฅผ ์ถœ๋ ฅ ๋ฒ”์œ„๋กœ ๋งคํ•‘ํ•˜๋Š” ๋ฐ ์‚ฌ์šฉํ•˜๋Š” ๋ฉ”์„œ๋“œ
        • ์• ๋‹ˆ๋ฉ”์ด์…˜๊ณผ ์ƒํ˜ธ์ž‘์šฉ์„ ๋™์ ์œผ๋กœ ์ œ์–ดํ•˜๊ณ  ๊ด€๋ฆฌํ•˜๊ธฐ ์œ„ํ•ด ์‚ฌ์šฉใ…‡
      • ๊ธฐ๋ณธํ˜• : const ๋ณ€์ˆ˜๋ช… = useTransform(๋ชจ์…˜๊ฐ’๋ณ€์ˆ˜๋ช…, ์ž…๋ ฅ๋ฐฐ์—ด, ์ถœ๋ ฅ๋ฐฐ์—ด);
        • ๋ชจ์…˜๊ฐ’๋ณ€์ˆ˜๋ช… : 'useMotionValue' ๊ฐ’
        • ์ž…๋ ฅ ๋ฐฐ์—ด : ์ž…๋ ฅ ๊ฐ’ ๋ฒ”์œ„
        • ์ถœ๋ ฅ ๋ฐฐ์—ด : ์ถœ๋ ฅ ๊ฐ’ ๋ฒ”์œ„
      • ์ž…๋ ฅ ๋ฒ”์œ„ ๋‚ด์— ์žˆ์„ ๋•Œ, ํ•ด๋‹น ๊ฐ’์— ๋Œ€ํ•œ ์ถœ๋ ฅ ๋ฒ”์œ„ ๊ฐ’์„ ๋ฐ˜ํ™˜ํ•จ
        • ์ž…๋ ฅ ๋ฒ”์œ„๋ฅผ ๋ฒ—์–ด๋‚˜๋„ ์ตœ์†Œ/์ตœ๋Œ€ ์ถœ๋ ฅ ๋ฒ”์œ„๋ฅผ ๋ฐ˜ํ™˜ํ•จ
        • ๋ฒ”์œ„ ๋‚ด์—์„œ๋Š” ์ ์ง„์ ์œผ๋กœ ๊ฐ’์„ ๋ฐ˜ํ™˜ํ•จ
    • useScroll()
      • ํ˜„์žฌ ํŽ˜์ด์ง€ ์Šคํฌ๋กค์˜ 'motion value'๊ฐ’์„ ๋ฐ˜ํ™˜ํ•˜๋Š” ๋ฉ”์„œ๋“œ
      • ๊ธฐ๋ณธํ˜• : const { ํ”„๋กœํผํ‹ฐ๋ช… } = useScroll();
        • scrollX, scrollY : ์ ˆ๋Œ€ ์Šคํฌ๋กค ์œ„์น˜๊ฐ’ [px]
        • scrollXProgress, scrollYProgress : ์ƒ๋Œ€ ์Šคํฌ๋กค ์œ„์น˜๊ฐ’ (0~1)
    • SVG Animation
      • <path>
        • 'fill' ์†์„ฑ : svg์˜ ์ƒ‰๊น”์„ ๋ณ€๊ฒฝ ๊ฐ€๋Šฅ
          • 'fill="currentColor"' : <svg>์˜ ์ƒ‰์ƒ์„ ์‚ฌ์šฉํ•˜๋ฉฐ, ๊ธฐ๋ณธ๊ฐ’์€ 'black'
            • <svg>์˜ 'color'์†์„ฑ์„ ํ†ตํ•ด ๋ณ€๊ฒฝ ๊ฐ€๋Šฅ
          • 'fill="transparent"' : ํˆฌ๋ช…
        • 'stroke' ์†์„ฑ : ํ…Œ๋‘๋ฆฌ์˜ ์ƒ‰๊น”์„ ๋ณ€๊ฒฝ ๊ฐ€๋Šฅ
        • 'strokeWidth' ์†์„ฑ : ํ…Œ๋‘๋ฆฌ์˜ ๋‘๊ป˜๋ฅผ ๋ณ€๊ฒฝ ๊ฐ€๋Šฅ
        • 'stroke', 'strokeWidth', 'fill' ๋“ฑ์€ CSS๋กœ ์˜ฎ๊ธธ ์ˆ˜ ์žˆ์Œ
      • SVG๋ฅผ animateํ•˜๊ธฐ ์œ„ํ•ด <motion.path>๋กœ ๋Œ€์ฒดํ•˜์—ฌ ์‚ฌ์šฉ
        • 'pathLength' ์†์„ฑ : ํ˜„์žฌ ์œ„์น˜๊นŒ์ง€์˜ path์˜ ๊ธธ์ด๋ฅผ ๋‚˜ํƒ€๋ƒ„ (0~1)
          • ์ด๋ฅผ ์‚ฌ์šฉํ•ด ํ…Œ๋‘๋ฆฌ๋ฅผ ๊ทธ๋ ค์ฃผ๋Š” animation ์‚ฌ์šฉ ๊ฐ€๋Šฅ
    • ํŠน์ • ํ”„๋กœํผํ‹ฐ์˜ transition ์‹œ๊ฐ„์„ ์ •ํ•˜๋Š” ๋ฐฉ๋ฒ•
      • ๊ธฐ๋ณธ์ ์œผ๋กœ ์ „์ฒด ์†์„ฑ์˜ animation ์‹œ๊ฐ„์ด ํ†ต์ผ๋˜์–ด ์žˆ์—ˆ์Œ
      • ๊ฐ๊ฐ์˜ ํ”„๋กœํผํ‹ฐ๋งˆ๋‹ค duration์ด๋‚˜ delay ์‹œ๊ฐ„์„ ์ง€์ •ํ•  ์ˆ˜ ์žˆ์Œ
      • ์‚ฌ์šฉ๋ฒ• : transition์—์„œ ๋ฐ”๊พธ๊ณ ์ž ํ•˜๋Š” ํ”„๋กœํผํ‹ฐ์— ์ง์ ‘ ํ• ๋‹น
        • ์ „์ฒด์— ๋Œ€ํ•œ animation์€ 'default'์— ํ• ๋‹น
        • ex. transition : { default : {duration : 5}, fill : {duration : 1} }
    • AnimatePresence
      • React์—์„œ ์‚ฌ๋ผ์ง€๋Š”(์—†์–ด์ง€๋Š”) ์ปดํฌ๋„ŒํŠธ๋ฅผ animateํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•จ
        • ๊ธฐ๋ณธ React์—์„œ๋Š” ์‚ฌ๋ผ์ง€๋Š” ์ปดํฌ๋„ŒํŠธ๋ฅผ animation์„ ๋ถ€์—ฌํ•  ์ˆ˜ ์—†์Œ
      • ๊ทœ์น™
        1. <AnimatePresence>๋Š” ํ•ญ์ƒ 'visible' ์ƒํƒœ์ด์–ด์•ผ ํ•จ
        2. <AnimatePresence>์˜ ๋‚ด๋ถ€์—๋Š” ์กฐ๊ฑด๋ฌธ์ด ์กด์žฌํ•ด์•ผ ํ•จ
      • ๊ธฐ๋ณธํ˜• : <AnimatePresence>{์กฐ๊ฑด ? ์ฐธ : ๊ฑฐ์ง“}</AnimatePresence>
        • ์กฐ๊ฑด๋ฌธ์— ๋“ค์–ด๊ฐ€๋Š” ์ปดํฌ๋„ŒํŠธ์— animation์„ ์ ์šฉํ•จ
        • ์ปดํฌ๋„ŒํŠธ๊ฐ€ ์‚ฌ๋ผ์งˆ ๋–„์˜ animation์€ 'exit' ์†์„ฑ์„ ์‚ฌ์šฉ
      • ์ปดํฌ๋„ŒํŠธ์— 'custom' ์†์„ฑ๊ฐ’์„ ๋„ฃ์–ด, variants์—์„œ ์กฐ๊ฑด๋ฌธ ์‚ฌ์šฉ ๊ฐ€๋Šฅ
        1. <motion.ํƒœ๊ทธ>์™€ <AnimatePresence> ๋‘˜๋‹ค 'custom' ์†์„ฑ์„ ๋ถ€์—ฌํ•˜์—ฌ ์‚ฌ์šฉ
        2. 'variants'๋ฅผ Object๋ฅผ returnํ•˜๋Š” ์ฝœ๋ฐฑํ•จ์ˆ˜๋กœ ์‚ฌ์šฉํ•ด์•ผํ•จ
        • ex. <AnimatePresence custom={isBack}> ย ย <Box custom={isBack} ... /> </AnimatePresence> const boxVariants = { ย ย entry : (isBack: Boolean) => ({ ย ย ย ย x : isBack ? -500 : 500; ย ย }), };
      • <AnimatePresence>์˜ 'mode="wait"' ํ”„๋กœํผํ‹ฐ
        • exit๊ฐ€ ์ผ์–ด๋‚œ ํ›„ entry๊ฐ€ ์ผ์–ด๋‚˜๋„๋ก ์„ค์ •ํ•˜๋Š” ํ”„๋กœํผํ‹ฐ
        • ๋ฏธ ์‚ฌ์šฉ ์‹œ exit์™€ entry๊ฐ€ ๋™์‹œ์— ์ผ์–ด๋‚จ
  • 23-09-15 : #8.14 ~ #9.4 / Animations(3)
    • Layout Animation
      • ์ปดํฌ๋„ŒํŠธ์— 'layout' ์†์„ฑ์„ ๋ถ€์—ฌ ์‹œ CSS์—์˜ํ•ด ํ•ด๋‹น ์ปดํฌ๋„ŒํŠธ์˜ layout์ด ๋ฐ”๋€” ๋•Œ ๋งˆ๋‹ค ์ž๋™์œผ๋กœ animation์ด ๋งŒ๋“ค์–ด์ง
      • ๊ธฐ๋ณธํ˜• : <์ปดํฌ๋„ŒํŠธ๋ช… layout />
    • Shared Layout Animation
      • ์„œ๋กœ ๋‹ค๋ฅธ ์ปดํฌ๋„ŒํŠธ์— ๊ฐ™์€ ๊ฐ’์„ ๊ฐ€์ง€๋Š” 'layoutId' ์†์„ฑ์„ ๋ถ€์—ฌ ์‹œ ํ•˜๋‚˜์˜ ์ปดํฌ๋„ŒํŠธ๋กœ ์—ฐ๊ฒฐํ•˜์—ฌ animation์„ ๋ณด์—ฌ์คŒ
        • ์‹œ๊ฐ์ ์œผ๋กœ ํ•˜๋‚˜์˜ ์—ฐ์† ์ปดํฌ๋„ŒํŠธ๋กœ ์ฒ˜๋ฆฌ๋จ
      • ๊ธฐ๋ณธํ˜• : <์ปดํฌ๋„ŒํŠธ๋ช… layoutId="๊ฐ’" />
  • 23-09-19 : #9.0 ~ #9.1 / NETFLIX Clone(1) - Setup
    • Font ํŒŒ์ผ ์ ์šฉ
      • .woff2, .ttf ๋“ฑ์˜ fontํŒŒ์ผ ์ ์šฉ ์‹œ 'src'ํด๋” ๋‚ด์— ํŒŒ์ผ์„ ์œ„์น˜์‹œ์ผœ์•ผ ํ•จ
      • '@font-face'๋ฌธ์„ ํ†ตํ•ด font๋ฅผ ์ •์˜
      • 'globalStyle' ๋ณด๋‹ค๋Š” 'cssํŒŒ์ผ'์— ์ •์˜ํ•ด์•ผ ์ดˆ๊ธฐ ๋กœ๋”ฉ ์„ฑ๋Šฅ์ด ํ–ฅ์ƒ๋จ
  • 23-09-21 : #9.2 / NETFLIX Clone(2) - Header
    • [Framer-Motion] Animation ๋ฐ˜๋ณต
      • CSS์˜ ๊ฐ’์„ ๋ฐฐ์—ดํ˜•์‹์œผ๋กœ ์ง€์ • ์‹œ ์ž๋™์œผ๋กœ ๊ฐ’์„ ๋ณ€ํ™˜ํ•˜๋Š” Animation์ฒ˜๋Ÿผ ์ž‘๋™ํ•จ
      • 'transition'์˜ 'repeat'ํ”„๋กœํผํ‹ฐ๋ฅผ ์‚ฌ์šฉํ•ด Animation ๋ฐ˜๋ณต ํšŸ์ˆ˜ ์ง€์ • ๊ฐ€๋Šฅ
        • number, "Infinity" ๋“ฑ
    • [React-Router-Dom] useMatch()
      • useMatch(URL์ฃผ์†Œ) : ํ˜„์žฌ ํŽ˜์ด์ง€๊ฐ€ ์–ด๋””์— ์œ„์น˜ํ•˜๋Š”์ง€ ์•Œ๋ ค์ฃผ๋Š” Hook
        • ํ˜„์žฌ ์ฃผ์†Œ์™€ ๊ฐ™์„ ์‹œ Object๋ฅผ ๋ฐ˜ํ™˜
        • ํ˜„์žฌ ์ฃผ์†Œ์™€ ๋‹ค๋ฅผ ์‹œ 'null'๊ฐ’์„ ๋ฐ˜ํ™˜
        • ์ƒ๋Œ€ ๊ฒฝ๋กœ, ์ ˆ๋Œ€ ๊ฒฝ๋กœ ๋‘˜๋‹ค ์‚ฌ์šฉ ๊ฐ€๋Šฅ
  • 23-09-22 : #9.3 ~ #9.8 / NETFLIX Clone(3) - Header & Home
    • [CSS] 'transform-origin' : ๋ณ€ํ™”๊ฐ€ ์‹œ์ž‘ํ•˜๋Š” ์œ„์น˜๋ฅผ ์ง€์ •ํ•˜๋Š” ์†์„ฑ
      • ๊ธฐ๋ณธํ˜• : transform-origin: ์„ธ๋กœ ๊ฐ€๋กœ;
    • [Framer-Motion] ํ•จ์ˆ˜๋กœ animation ์ œ์–ดํ•˜๊ธฐ
      • useAnimation() : animation์˜ ์ œ์–ด๋ฅผ ํ•จ์ˆ˜๋กœ ์ œ์–ดํ•˜๋„๋ก ํ•จ
        • ๊ธฐ์กด์—๋Š” ์ปดํฌ๋„ŒํŠธ์— ์†์„ฑ์„ ๋ถ€์—ฌํ•˜์˜€์Œ
        • ์—ฌ๋Ÿฌ ๊ฐœ์˜ animation์„ ๋™์‹œ์— ์‹คํ–‰์‹œํ‚ค๊ณ  ์‹ถ์„ ๋•Œ ์œ ์šฉํ•จ
      • ๊ธฐ๋ณธํ˜• ์„ ์–ธ : const ๋ณ€์ˆ˜๋ช… = useAnimation(); ์‚ฌ์šฉ : ๋ณ€์ˆ˜๋ช….ํ”„๋กœํผํ‹ฐ({์Šคํƒ€์ผ}) ์ ์šฉ : <์ปดํฌ๋„ŒํŠธ๋ช… animate={๋ณ€์ˆ˜๋ช…} />
      • const inputAnimation = useAnimation(); const toggleSearch = () => { ย ย  if (searchOpen) { ย ย ย ย inputAnimation.start({ scaleX: 0 }); ย ย } else { ย ย ย ย inputAnimation.start({ scaleX: 1 }); ย ย } ย ย ย ย setSearchOpen((prev) => !prev); }; <Input initial={{ scaleX: 0 }} animate={inputAnimation} />

      • 'useMotionValueEvent()' ๋ฉ”์„œ๋“œ๋ฅผ ํ†ตํ•œ ์ œ์–ด๋กœ, variants ์‚ฌ์šฉ๋„ ๊ฐ€๋Šฅ
    • [React-Query] ์˜ํ™” API
      • 'TMDB'์‚ฌ์ดํŠธ๋กœ๋ถ€ํ„ฐ ์˜ํ™” API๋ฅผ ์‚ฌ์šฉ
      • React-Query ์‚ฌ์šฉ๋ฒ•
        1. 'query client'๋ฅผ ๋งŒ๋“ค๊ณ , <QueryClientProvider>๋กœ ๊ฐ์‹ธ์ฃผ๊ธฐ
        2. fetcherํ•จ์ˆ˜ ์ •์˜ํ•˜๊ธฐ
        3. 'useQuery()'๋ฅผ ์‚ฌ์šฉํ•ด API ๋ฐ์ดํ„ฐ ๊ฐ€์ ธ์˜ค๊ธฐ
          • ๊ธฐ๋ณธํ˜• : const { isLoading, data, error } = useQuery<์ œ๋„ค๋ฆญ>([์ฟผ๋ฆฌํ‚ค๋ช…], fetcherํ•จ์ˆ˜, ?์˜ต์…˜);
        4. ๋ฐ›์€ ๋ฐ์ดํ„ฐ์˜ ํƒ€์ž… ์„ค๋ช…ํ•˜๊ธฐ
          • 'interface'๋ฅผ ์‚ฌ์šฉํ•ด ๋ฐ์ดํ„ฐํƒ€์ž… ์ •์˜
    • [Framer-Motion] ๋น ๋ฅธ ์‹œ๊ฐ„ ๋‚ด์˜ ์—ฐ์†๋œ animation ์ค‘์ฒฉ ํ˜„์ƒ ๋ฌธ์ œ
      • <AnimatePresence>์˜ 'onExitComplete'์†์„ฑ์€ exit๊ฐ€ ๋๋‚œ ํ›„ ์‹คํ–‰๋จ
        • animation์ด ์‹คํ–‰๋˜๋Š” ๋™์•ˆ ๋™์ž‘์„ ๋ง‰๋„๋ก ํ•จ
    • [Framer-Motion] ์ตœ์ดˆ ๋ Œ๋”๋ง ์‹œ์˜ animation ํ•ด์ œ
      • <AnimatePresence>์˜ 'initial'์†์„ฑ๊ฐ’์„ 'false'๋กœ ์ค„ ์‹œ ์ตœ์ดˆ ๋ Œ๋”๋ง ์‹œ์˜ animation์„ ํ•ด์ œํ•จ
    • ์˜ํ™” ๋ฆฌ์ŠคํŠธ์— ์˜ํ™”๋“ค ๋„ฃ๊ธฐ
      • ์˜ํ™”๋ฆฌ์ŠคํŠธ ๋ฐฐ์—ด์„ ์Šฌ๋ผ์ด๋” ๋ฐฐ์—ด์˜ ๊ฐฏ์ˆ˜(offset)๋งŒํผ ์ž˜๋ผ์„œ ์—ฌ๋Ÿฌ ํŽ˜์ด์ง€(page)๋ฅผ ๋งŒ๋“ค์–ด์•ผ ํ•จ
        • ๋ฐฐ๊ฒฝ์œผ๋กœ ์‚ฌ์šฉํ•œ ์ฒซ ๋ฒˆ์งธ ์ธ๋ฑ์Šค๋Š” ์ œ์™ธ : data?.results.slice(1);
      • '๋ฐฐ์—ด.slice(์‹œ์ž‘์ธ๋ฑ์Šค, ๋์ธ๋ฑ์Šค)' ๋ฉ”์„œ๋“œ๋ฅผ ์‚ฌ์šฉํ•ด ๋ฐฐ์—ด์„ ์ž˜๋ผ์„œ ์‚ฌ์šฉ
        • '๋ฐฐ์—ด.slice(offset*page, offset*page+offset);'์„ ์‚ฌ์šฉํ•˜๊ณ , page๋ฅผ 1์”ฉ ์ฆ๊ฐ€
  • 23-09-23 : #9.9 ~ #9.10 / NETFLIX Clone(4) - Box animations
    • [CSS] ์˜ํ™” ๋ฆฌ์ŠคํŠธ์—์„œ ์˜ํ™”๋ฅผ hover ์‹œ scale์„ ์ปค์ง€๊ฒŒ ํ•  ๋•Œ, ์–‘ ๋์— ์กด์žฌํ•˜๋Š” ์˜ํ™”๊ฐ€ ํ™”๋ฉด์ด ์ž˜๋ฆฌ๋Š” ํ˜„์ƒ
      • ์ฒซ ๋ฒˆ์งธ, ๋งˆ์ง€๋ง‰ ์š”์†Œ์— 'transform-origin' ์†์„ฑ์„ ์‚ฌ์šฉ
  • 23-09-25 : #9.11 ~ #9.15 / NETFLIX Clone(5) - Movie modal & Search Form
  • 23-09-26 : NETFLIX Clone(6)
    • Update : [Header] ๊ฒ€์ƒ‰์ฐฝ์„ ์—ด ์‹œ ์ž๋™์œผ๋กœ ์ž…๋ ฅ์ฐฝ์— focus
  • 23-09-27 : NETFLIX Clone(7)
    • Update
      • [Header]
        • ๊ฒ€์ƒ‰์ฐฝ ๋ฐ”๊นฅ์„ ํด๋ฆญ ์‹œ ์—ด๋ ค์žˆ๋Š” ๊ฒ€์ƒ‰์ฐฝ์„ ๋‹ซ๋„๋ก ํ•จ + ๋‹ซ์„ ์‹œ ์ž…๋ ฅ๋œ ๋‚ด์šฉ ์ดˆ๊ธฐํ™”
        • ๊ฒ€์ƒ‰ ๊ธฐ๋Šฅ ์—…๋ฐ์ดํŠธ
        • ๊ฒ€์ƒ‰์ฐฝ์— ๊ฐ’์ด ์žˆ์„ ์‹œ์—๋งŒ ๊ฒ€์ƒ‰๊ฐ’์„ ๋น„์šธ ์ˆ˜ ์žˆ๋Š” 'x'๋ฒ„ํŠผ ์ƒ์„ฑ
        • ๊ฒ€์ƒ‰ ์กฐ๊ฑด ๋ฏธ๋‹ฌ ์‹œ error๋ฅผ ๋ณด์—ฌ์ฃผ๋Š” message ์ƒ์„ฑ
      • [Search]
        • API ๊ฒฐ๊ณผ๊ฐ’์˜ interface ์ •์˜
        • ์ธ๋ฌผ ๊ฒ€์ƒ‰ ์‹œ ๊ด€๋ จ ์ž‘ํ’ˆ์„ '.map()'์„ ํ†ตํ•ด ํ’€์–ด์„œ ํ™”๋ฉด์— ๋ณด์—ฌ์คŒ
          • ์˜ํ™”, tv์‡ผ ๋“ฑ ์—ฌ๋Ÿฌ API๋ฅผ ๊ฐ๊ฐ ์‚ฌ์šฉํ•  ํ•„์š”์—†์ด ํ•˜๋‚˜์˜ API ์‚ฌ์šฉ์œผ๋กœ ํ•ด๊ฒฐ
    • Fix
      • [Header] ๊ฒ€์ƒ‰์ฐฝ์ด ์—ด๋ฆด ์‹œ ์šฐ์ธก ๋ถ€๋ถ„์ด form์— ๊ฐ€๋ ค์ ธ input์ด ํด๋ฆญ์ด ์•ˆ ๋˜๋Š” ํ˜„์ƒ ์ˆ˜์ •
      • [Search] ๊ฒ€์ƒ‰ ์‹œ ๋™์ผ ์ž‘ํ’ˆ์ด ์ค‘๋ณต๋˜๋Š” ํ˜„์ƒ ์ˆ˜์ • (์ค‘๋ณต ๊ฒฐ๊ณผ ์ œ๊ฑฐ)
        • ๋ฉ€ํ‹ฐ ๊ฒ€์ƒ‰์ด๊ธฐ ๋•Œ๋ฌธ์—, ์ž‘ํ’ˆ/์ธ๋ฌผ ๊ฒ€์ƒ‰์œผ๋กœ ์ธํ•ด ์ค‘๋ณต๋˜๋Š” ๊ฒƒ์œผ๋กœ ์ถ”์ •
        • ์ค‘๋ณต ์‹œ ํ•˜๋‚˜๋งŒ ๋ณด์—ฌ์ฃผ๋„๋ก ์ˆ˜์ •
    • Issue : [Search] ์žฅ๋ฅด ๊ฒ€์ƒ‰ ๊ด€๋ จ ์„ค์ •ํ•˜๊ธฐ
  • 23-09-28 : NETFLIX Clone(8)
    • Update : [Search] ๊ฒ€์ƒ‰ UI ์—…๋ฐ์ดํŠธ & ํฌ์Šคํ„ฐ ์ด๋ฏธ์ง€๊ฐ€ ์—†๋Š” ์ž‘ํ’ˆ์˜ ๋Œ€์ฒด ์ด๋ฏธ์ง€
    • Fix : [Header] ๊ฒ€์ƒ‰์ฐฝ์˜ ๊ฒ€์ƒ‰ ํ‚ค์›Œ๋“œ๊ฐ€ ์šฐ์ธก์˜ 'x'๋ฒ„ํŠผ๊ณผ ๊ฒน์น˜๋Š” ํ˜„์ƒ ์ˆ˜์ •
    • Issue : [Search] ๊ฒ€์ƒ‰ ๊ฒฐ๊ณผ์˜ ๊ฐฏ์ˆ˜
  • 23-09-29 : NETFLIX Clone(9)
    • Update : [Search] ์•„์ดํ…œ hover ์‹œ์˜ infoBox ์—…๋ฐ์ดํŠธ
    • Fix : [Search] ๊ฒ€์ƒ‰ ๊ฒฐ๊ณผ์˜ ๊ฐฏ์ˆ˜
  • 23-10-02 : NETFLIX Clone(10)
    • Update
      • [Slider] ์Šฌ๋ผ์ด๋” ์ขŒ/์šฐ ๋ฒ„ํŠผ ์ƒ์„ฑ ๋ฐ ์• ๋‹ˆ๋ฉ”์ด์…˜ ์—…๋ฐ์ดํŠธ
      • [Banner] ์˜ํ™”/TV ๋‘˜ ๋‹ค ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•˜๋„๋ก ์—…๋ฐ์ดํŠธ
    • Fix : [Modal-Box] z-index ์ˆ˜์ •
  • 23-10-04 : NETFLIX Clone(11)
    • Fix : [Slider] absolute์ธ ์ž์‹ ์š”์†Œ์˜ height๋ฅผ ๋ถ€๋ชจ ์š”์†Œ์˜ height์— ์ ์šฉ(padding-bottom ์‚ฌ์šฉ)ํ•ด ์Šฌ๋ผ์ด๋” ์ขŒ/์šฐ ๋ฒ„ํŠผ์˜ ๋†’์ด๋ฅผ ๊ฐ™๊ฒŒ ๋งŒ๋“ฆ
    • Update : [Slider] hover ์‹œ infoBox / click ์‹œ infoBox ๊ธฐ์ดˆ์ž‘์—…
  • 23-10-05 : NETFLIX Clone(12)
    • Update
      • [Modal-Box]
        • ๋ฐ์ดํ„ฐ ์ถ”๊ฐ€ ๋ฐ UI ์—…๋ฐ์ดํŠธ
        • Nested-Router ๋ถ„ํ•  ์ •๋ณต
        • ํ™ˆ์—์„œ ์ด๋ฏธ API data๋ฅผ ๊ฐ€์ง€๊ณ  ์žˆ๋‹ค๋ฉด ๋ฐ”๋กœ ์‚ฌ์šฉ / URL ๊ฒ€์ƒ‰ ์‹œ API ๊ฒ€์ƒ‰
    • Issue : [Modal-Box] URL ์ง์ ‘ ์ž…๋ ฅ ์‹œ 404 Error ํ•ด๊ฒฐํ•˜๊ธฐ
  • 23-10-08 : NETFLIX Clone(13)
    • Issue : [Modal-Box] ์Šคํฌ๋กค๋ฐ” ๋ฌธ์ œ
  • 23-10-11 : NETFLIX Clone(14)
    • Fix : [Modal-Box]
      • recommendationData๊ฐ€ ์žˆ์„ ๊ฒฝ์šฐ ์Šคํฌ๋กค๋ฐ”๊ฐ€ ์ƒ๊ธฐ์ง€ ์•Š๋Š” ๋ฌธ์ œ ํ•ด๊ฒฐ
        • ์ƒ์œ„ ์ปจํ…Œ์ด๋„ˆ <Movie>์—๊ฒŒ 'recommendationData?.result.length'์— ๋”ฐ๋ผ ์ฐธ์ผ ๊ฒฝ์šฐ, 'height:100%'๋ฅผ ์„ ์–ธ
      • URL ์ง์ ‘ ์ž…๋ ฅ ์‹œ 404 Error ๋ฌธ์ œ ํ•ด๊ฒฐ
        • detail๊ณผ credit API data๊ฐ€ ์—†์„ ์‹œ ํ™”๋ฉด์„ ๋ณด์—ฌ์ฃผ์ง€ ์•Š๊ฒŒ ์กฐ๊ฑด๋ฌธ ์žฌ์„ค์ •
    • Update
      • [Modal-Box] ์ถ”์ฒœ ํŽ˜์ด์ง€ ์—…๋ฐ์ดํŠธ
      • [Slider] ๋ถ„ํ• ์ •๋ณต
  • 23-10-12 : NETFLIX Clone(15)
    • Update
      • [Slider]
        • ์Šฌ๋ผ์ด๋” ํƒ€์ดํ‹€ ์ถ”๊ฐ€
        • ์ฒซ ์Šฌ๋ผ์ด๋”๋งŒ 2๋ฒˆ์งธ ๋ฐ์ดํ„ฐ๋ถ€ํ„ฐ ๋ณด์—ฌ์คŒ (์ฒซ๋ฒˆ์งธ ๋ฐ์ดํ„ฐ๋Š” Banner๋กœ ์‚ฌ์šฉ)
      • [Modal-Box] movie, tv ๋‘˜ ๋‹ค์—์„œ ๋ชจ๋‹ฌ๋ฐ•์Šค๊ฐ€ ๋‚˜์˜ค๊ฒŒ ์—…๋ฐ์ดํŠธ
      • [Home, TV] ๋” ๋งŽ์€ ์Šฌ๋ผ์ด๋“œ ์—…๋ฐ์ดํŠธ
      • [Footer] ์—…๋ฐ์ดํŠธ
    • Fix : [Slider] ๊ฐ๊ธฐ ๋‹ค๋ฅธ ์Šฌ๋ผ์ด๋”์—์„œ ๊ฐ™์€ ์˜ํ™”๊ฐ€ ์žˆ์„ ์‹œ ์„œ๋กœ ์• ๋‹ˆ๋ฉ”์ด์…˜์„ ๊ฐ„์„ญํ•˜๋Š” ํ˜„์ƒ ์ˆ˜์ •
      • 'LayoutId'๊ฐ€ ์ค‘๋ณต๋˜์ง€ ์•Š๋„๋ก ์ˆ˜์ •
  • 23-10-13 : NETFLIX Clone(16)
    • Update
      • [Banner] ์žฌ์ƒ ๋ฒ„ํŠผ, ์ƒ์„ธ ์ •๋ณด ๋ฒ„ํŠผ ์—…๋ฐ์ดํŠธ
      • [Item] ์žฌ์ƒ ๋ฒ„ํŠผ ํด๋ฆญ ์‹œ ์˜ˆ๊ณ ํŽธ ์˜์ƒ(YouTube) ๋ณด์—ฌ์ฃผ๊ธฐ ์—…๋ฐ์ดํŠธ
  • 23-10-16 : NETFLIX Clone(17)
    • Fix
      • [Info-Box] hover ์‹œ ํ•˜๋‹จ์˜ ์Šฌ๋ผ์ด๋“œ๋ณด๋‹ค ๋ ˆ์ด์–ด๊ฐ€ ๋’ค์— ์žˆ๋Š” ํ˜„์ƒ ์ˆ˜์ •
      • [Iframe] ์ •๊ฐ€์šด๋ฐ ์ •๋ ฌ
    • Update
      • [ClickedItem] ์˜ํ™”์™€ tv๋ฅผ ํ•œ ์ปดํฌ๋„ŒํŠธ๋กœ ํ†ตํ•ฉ
      • [Search] ๊ฒ€์ƒ‰๋œ item ํด๋ฆญ ์‹œ modal-box ๋ณด์—ฌ์ฃผ๊ธฐ
    • Issue : [Search] ๊ฒ€์ƒ‰๋œ item์˜ modal-box์—์„œ recommendItem ํด๋ฆญ ์‹œ URL ์ด๋™ํ•˜๋Š” ํ˜„์ƒ
      • ๊ฒ€์ƒ‰ ์‹œ ๊ฒ€์ƒ‰์–ด๋ฅผ Query String ๋Œ€์‹  ํ•˜์œ„ ๋™์ URL ๋ฐ nested route ์‚ฌ์šฉ?
  • 23-10-17 : NETFLIX Clone(18)
    • Fix : [Search] ๊ฒ€์ƒ‰๋œ item ํด๋ฆญ ์‹œ overlay ์œ„์น˜ ์ˆ˜์ •
  • 23-10-18 : NETFLIX Clone(19)
    • Fix
      • [Iframe] ์ค‘๋ณต๋œ key๊ฐ’์„ ๊ฐ€์ง€๋Š” ํ˜„์ƒ ์ˆ˜์ •
      • [Modal-Box] recommend item๋“ค์˜ height๊ฐ’ ์ˆ˜์ • (max-height)
    • Update : [TV, Modal-Box] Season ๋ฐ Episode ์—…๋ฐ์ดํŠธ (1/2)
      • API ๊ฐ€์ ธ์˜ค๊ธฐ ๋ฐ ์ „์ฒด์ ์ธ ํฐ ํ‹€ ์ œ์ž‘
    • Issue : [TV, Season] select svg ์• ๋‹ˆ๋ฉ”์ด์…˜ ๋งŒ๋“ค๊ธฐ
  • 23-10-20 : NETFLIX Clone(20)
    • Update
      • [Modal-Box] ์Šคํฌ๋กค๋ฐ” ๊ธฐ๋Šฅ์„ ์œ ์ง€ํ•˜๋ฉด์„œ, ํ™”๋ฉด์— ์ˆจ๊ธฐ๊ธฐ
      • [TV, Modal-Box] Season ๋ฐ Episode ์—…๋ฐ์ดํŠธ (2/2)
        • ์„ธ๋ถ€์‚ฌํ•ญ ๊พธ๋ฏธ๊ธฐ
        • ์‚ฌ์ง„์ด ์—†์„ ์‹œ ํ…์ŠคํŠธ๋กœ ๋Œ€์ฒด
        • ์ฒ˜์Œ 10๊ฐœ ๊นŒ์ง€๋งŒ ๋ณด์—ฌ์ฃผ๊ณ , ๋ฒ„ํŠผ ํด๋ฆญ ์‹œ ํ•ด๋‹น ์‹œ์ฆŒ์˜ ์—ํ”ผ์†Œ๋“œ ๋‹ค ๋ณด์—ฌ์ฃผ๊ธฐ
      • [Head] <title> ์—…๋ฐ์ดํŠธ
  • 23-10-21 : NETFLIX Clone(21)
    • Update : [Head] favicon ์—…๋ฐ์ดํŠธ
    • Fix
      • [Head] 'description' ๋ณ€๊ฒฝ
      • [Banner] ๋ฐฐ๋„ˆ ์ด๋ฏธ์ง€ ์ค‘์•™์œผ๋กœ ์ •๋ ฌ
      • [Slider] ๋ฒ„ํŠผ ์ƒ‰๊น” ๋ณ€๊ฒฝ
      • [Footer] github ๋งํฌ ๋ฐ 'MenuBox'์˜ <li>์˜ width ์ˆ˜์ •

๋…ธ๋งˆ๋“œ ์ฝ”๋” ์ •์ฑ… ์ƒ ๊ฐ•์˜์š”์•ฝ์€ ๊ดœ์ฐฎ์œผ๋‚˜, ์ฝ”๋“œ์™€ ํ•„๊ธฐ๋Š” ๊ณต๊ฐœ์ ์ธ ๊ณณ์— ์˜ฌ๋ฆฌ๋ฉด ์•ˆ ๋จ.
ํ•„๊ธฐ ์š”์•ฝ์ง€๋Š” ์•”ํ˜ธํ™”๋œ .zip ํŒŒ์ผ๋กœ ์ €์žฅํ•จ.

Releases

No releases published

Packages

 
 
 

Contributors