Post

[Day50] useState, ๊ณ ์ฐจํ•จ์ˆ˜

[Day50] useState, ๊ณ ์ฐจํ•จ์ˆ˜

๐Ÿ”ธ goTrip ์‹ค์Šต - React

๋””์ž์ด๋„ˆ์™€ ์™€์ด์–ดํ”„๋ ˆ์ž„์œผ๋กœ ์˜๊ฒฌ์„ ๋‚˜๋ˆŒ ๋•Œ ๋ถ€ํ„ฐ ๊ฐœ๋ฐœํ•ด์•ผํ•˜๋Š” ๊ธฐ๋Šฅ์„ ์š”์•ฝํ•ด๋‘๋Š”๊ฒŒ ์ข‹์Œ

goTrip ๊ธฐ๋Šฅ ์š”์•ฝ

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


useState์™€ ์ƒํƒœ ๋ถˆ๋ณ€์„ฑ

1
2
3
4
5
6
const changeText = () => {
  setData(prev => [...prev, 'test'])

  setAge(prev => prev + num) // โœ… ์ด์ „ ๊ฐ’์„ ๊ธฐ๋ฐ˜์œผ๋กœ ์—…๋ฐ์ดํŠธ
  setAge(age + num)          // โš ๏ธ ์—…๋ฐ์ดํŠธ๊ฐ€ ๋น„๋™๊ธฐ๋ผ ์˜ˆ์ธก ๋ถˆ๊ฐ€
}

์ž‘๋™ ๋ฐฉ์‹

  • prev: ์ด์ „ ๋ฐ์ดํ„ฐ ์ƒํƒœ
  • [...prev, 'test']: ๊ธฐ์กด ๋ฐ์ดํ„ฐ๋ฅผ ๋ณต์ œ ํ›„ ์ƒˆ๋กœ์šด ๊ฐ’ ์ถ”๊ฐ€
  • setData(โ€ฆ) : ์ƒํƒœ ์—…๋ฐ์ดํŠธ โ†’ ์ปดํฌ๋„ŒํŠธ ์žฌ๋ Œ๋”๋ง
  • โ—๏ธ ์ดˆ๊ธฐ ์ƒํƒœ(๊ธฐ์กด ๋ฐฐ์—ด)๋Š” ์ง์ ‘ ๋ณ€๊ฒฝํ•˜๋ฉด ์•ˆ ๋จ โ†’ ๋ถˆ๋ณ€์„ฑ ์œ ์ง€ ํ•„์ˆ˜!

๐Ÿš• InputFild ์ปดํฌ๋„ŒํŠธ

์œ ํšจ์„ฑ ๊ฒ€์‚ฌ ๋ฆฌํŒฉํ† ๋ง (์‚ผํ•ญ ์—ฐ์‚ฐ์ž ์‚ฌ์šฉ)

๊ธฐ์กด ์ฝ”๋“œ ์กฐ๊ฑด๋ฌธ

1
2
3
4
5
6
7
8
9
if (inputText.trim() === '') {
  alert('์—ฌํ–‰์ง€๋ฅผ ์ž…๋ ฅํ•˜์„ธ์š”')
  document.querySelector('input').focus()
  return
} else if (inputText.trim().length < 2) {
  alert('2์ž ์ด์ƒ๋กœ ์ž…๋ ฅํ•˜์„ธ์š”')
  document.querySelector('input').focus()
  return
}

โžก ์ด๊ฑธ ์‚ผํ•ญ ์—ฐ์‚ฐ์ž๋กœ ๋ฆฌํŒฉํ† ๋ง

1
2
3
4
5
if (inputText.trim().length < 2) {
  alert(inputText.trim() === '' ? '์—ฌํ–‰์ง€๋ฅผ ์ž…๋ ฅํ•˜์„ธ์š”' : '2์ž ์ด์ƒ์œผ๋กœ ์ž…๋ ฅํ•˜์„ธ์š”');
  document.querySelector('input').focus();
  return;
}

input๊ณผ label์„ ๊ฐ™์ด ์‚ฌ์šฉํ•˜๊ธฐ๋„ ํ•จ

input๊ณผ label์„ ํ•จ๊ป˜ ์‚ฌ์šฉํ•˜๋ฉด ์ ‘๊ทผ์„ฑ๊ณผ UX๊ฐ€ ํ–ฅ์ƒ๋จ. label์˜ htmlFor๋Š” input์˜ id์™€ ์—ฐ๊ฒฐ๋จ

1
2
3
4
5
6
7
8
9
10
11
<div className="inputFild mw">
  <label htmlFor="fild">์—ฌํ–‰์ง€ ์ž…๋ ฅ</label>
  <input
    placeholder="์—ฌํ–‰์ง€๋ฅผ ์ž…๋ ฅํ•˜์„ธ์š”"
    type="text"
    id="fild"
    onChange={inputItem}
  />
  <button onClick={addItem}>์ž…๋ ฅ</button>
</div>

  • ์‚ฌ์šฉ์ž๊ฐ€ label ํด๋ฆญํ•ด๋„ input์— ํฌ์ปค์Šค๊ฐ€ ๊ฐ
  • ์‹œ๊ฐ์žฅ์• ์ธ์šฉ ์Šคํฌ๋ฆฐ๋ฆฌ๋”์— ์ ์ ˆํžˆ ์ธ์‹๋จ

InputFild.jsx ์ „์ฒด ์ฝ”๋“œ

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
import React, { useState } from 'react'

const InputFild = ({ setData }) => {
  const [inputText, setInputText] = useState('');

  // ์ž…๋ ฅ๊ฐ’์„ ์ƒํƒœ์— ์‹ค์‹œ๊ฐ„ ๋ฐ˜์˜
  const inputItem = e => {
    setInputText(e.target.value)
  }

  const addItem = () => {
    // ์ž…๋ ฅ๊ฐ’ ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ
    if (inputText.trim().length < 2) {
      alert(inputText.trim() === '' ? '์—ฌํ–‰์ง€๋ฅผ ์ž…๋ ฅํ•˜์„ธ์š”' : '2์ž ์ด์ƒ๋กœ ์ž…๋ ฅํ•˜์„ธ์š”')
      document.querySelector('input').focus() // ํฌ์ปค์Šค๋ฅผ ๋‹ค์‹œ input์— ์คŒ
      return
    }
    setData(prev => [inputText, ...prev]) // ๊ธฐ์กด ๋ฆฌ์ŠคํŠธ ์•ž์— ์ถ”๊ฐ€ํ•ด์„œ ์ƒˆ๋กœ์šด ๋ฐฐ์—ด๋กœ ๋ฐ˜ํ™˜
    setInputText('')
    document.querySelector('input').focus()
  }

  const handleKeyup = e => {
    if (e.key === 'Enter') addItem()
  }

  return (
    <div className="inputFild mw">
      <input
        type="text"
        placeholder="์—ฌํ–‰์ง€๋ฅผ ์ž…๋ ฅํ•˜์„ธ์š”"
        value={inputText}
        onChange={inputItem}
        onKeyUp={handleKeyup}
      />
      <button onClick={addItem}>์ž…๋ ฅ</button>
    </div>
  )
}

export default InputFild

๐Ÿ”‘ onKeyDown vs onKeyUp

์ด๋ฒคํŠธ๋ฐœ์ƒ ์‹œ์ ํŠน์ง•
onKeyDownํ‚ค๋ฅผ ๋ˆŒ๋ €์„ ๋•Œ- ๊ฐ€์žฅ ๋จผ์ € ๋ฐœ์ƒ
- ๊พน ๋ˆ„๋ฅด๊ณ  ์žˆ์œผ๋ฉด ๋ฐ˜๋ณต ๋ฐœ์ƒ
onKeyUpํ‚ค๋ฅผ ๋—์„ ๋•Œ- ํ•œ ๋ฒˆ๋งŒ ๋ฐœ์ƒ
- ๋ˆ„๋ฅด๊ณ  ์žˆ๋Š” ๋™์•ˆ์€ ์•ˆ ๋ฐœ์ƒ

๐Ÿš• ์‚ญ์ œ ๊ธฐ๋Šฅ

๋ฆฌ์ŠคํŠธ์—์„œ ํŠน์ • ํ•ญ๋ชฉ ์‚ญ์ œ ์‹œ filter()๋ฅผ ํ™œ์šฉ

1
setData(prev => prev.filter(item => item !== area))

๐Ÿ›‘ ๋‚ด๊ฐ€ ๊ณ„์† ์—๋Ÿฌ๊ฐ€ ๋œฌ ์ฝ”๋“œ

1
2
3
setData(prev => {
    prev.filter(item => item !== area)
})
  • ์ด ์ฝ”๋“œ๋Š” ์ƒˆ๋กœ์šด ์ƒํƒœ๊ฐ’์„ ๋ฆฌํ„ดํ•˜์ง€ ์•Š์Œ.
  • setData์˜ ์ธ์ž๋กœ ์ „๋‹ฌ๋œ ํ•จ์ˆ˜๋Š” ์ƒˆ๋กœ์šด ์ƒํƒœ๊ฐ’์„ ๋ฆฌํ„ดํ•ด์•ผ ํ•˜๋Š”๋ฐ, filter ๊ฒฐ๊ณผ๋ฅผ ๋ฐ˜ํ™˜ํ•˜์ง€ ์•Š๊ณ  ๋๋‚จ โ†’ undefined ๋ฆฌํ„ด๋จ.
  • ๋”ฐ๋ผ์„œ setData(undefined)๊ฐ€ ํ˜ธ์ถœ๋ผ์„œ ๋น„์ •์ƒ ๋™์ž‘

โœ… ์˜ฌ๋ฐ”๋ฅธ ๋ฐฉ์‹

1
2
3
4
5
6
setData(prev => {
    return prev.filter(item => item !== area)
})

// ๋˜๋Š”
setData(prev => prev.filter(item => item !== area))

์ „์ฒด ์ฝ”๋“œ (src/components/List.jsx)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import React from 'react'

const List = ({ area, setData }) => {
  const removeItem = () => {
    setData(prev => {
      const newData = prev.filter(item => item !== area)
      localStorage.setItem('trip', JSON.stringify(newData))
      return newData
    })
  }
  return (
    <li>
      <p>{area}</p>
      <i className="fa-solid fa-trash-can" onClick={removeItem}></i>
    </li>
  )
}

export default List

โœ… localstorage

  • setItem : ๊ฐ’ ์ €์žฅ (JSON ๋ฌธ์ž์—ด๋กœ ๋ณ€ํ™˜ํ•ด์„œ ์ €์žฅ)
  • getItem : ๊ฐ’ ์ฝ๊ธฐ (ํŒŒ์‹ฑํ•ด์„œ ์‚ฌ์šฉ)

์ถ”๊ฐ€ํ•  ๋•Œ

1
2
3
4
5
setData(prev => {
  const newData = [...prev, inputText]
  localStorage.setItem('trip', JSON.stringify(newData))
  return newData
})

์‚ญ์ œํ•  ๋•Œ

1
2
3
4
5
setData(prev => {
  const newData = prev.filter(item => item !== area)
  localStorage.setItem('trip', JSON.stringify(newData))
  return newData
})

๋ถˆ๋Ÿฌ์˜ฌ ๋•Œ

1
const list = JSON.parse(localStorage.getItem('trip')) || []

๋กœ๋ ˜ ํ”ฝ์ˆจ (Lorem Picsum)

๋žœ๋ค ์ด๋ฏธ์ง€ ์ƒ์„ฑ url Lorem Picsum

๋žœ๋ค ์ด๋ฏธ์ง€ url ๊ฐ€์ ธ์™€์„œ ์‚ฌ์šฉํ•˜๋ฉด ๋จ !


CSS Modules

  • CSS ๋ชจ๋“ˆ์„ ์‚ฌ์šฉํ•˜๋ฉด ์ปดํฌ๋„ŒํŠธ ๋‹จ์œ„๋กœ ์Šคํƒ€์ผ์„ ์บก์Аํ™”ํ•  ์ˆ˜ ์žˆ์Œ
  • ํด๋ž˜์Šค ์ด๋ฆ„์ด ์ž๋™์œผ๋กœ ๊ณ ์œ ํ•˜๊ฒŒ ๋งŒ๋“ค์–ด์ง€๊ธฐ ๋•Œ๋ฌธ์— ์ถฉ๋Œ ๊ฑฑ์ • ์—†์ด ์žฌ์‚ฌ์šฉ ๊ฐ€๋Šฅ
  • ํŒŒ์ผ๋ช…์„ [์ปดํฌ๋„ŒํŠธ์ด๋ฆ„].module.css ํ˜•์‹์œผ๋กœ ์ €์žฅํ•˜๊ณ  ์‚ฌ์šฉ

sample.module.css

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
.imgCon {
  border: 1px solid red;
  width: 200px;
  height: 200px;
  margin: 1rem;
  position: relative;
  overflow: hidden;
  border-radius: 2rem;
} 

.imgCon > * {
  position: absolute;
}

.imgCon img {
  opacity: 0.5;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

jsxํŒŒ์ผ์— ์ ์šฉ - App.jsx

1
2
3
4
5
6
7
import css from './sample.module.css'

<div className={css.imgCon}>
  <p>{userInfo.artwork.title}</p>
  <p>{userInfo.artwork.artist}</p>
  <img src={userInfo.artwork.imgUrl} alt={userInfo.artwork.title} />
</div>

์ „์—ญ CSS์™€ ํ•จ๊ป˜ ์“ฐ๊ธฐ

<div className={`${css.imgCon} mw`}>

  • css.imgCon: CSS Module๋กœ ๋ถˆ๋Ÿฌ์˜จ ํด๋ž˜์Šค
  • mw: ์ „์—ญ์œผ๋กœ ์„ ์–ธํ•œ ํด๋ž˜์Šค (max-width ๋“ฑ)

CSS Modules ์‚ฌ์šฉ ์ด์œ 

  • ์ปดํฌ๋„ŒํŠธ๋งˆ๋‹ค ๊ณ ์œ ํ•œ ํด๋ž˜์Šค ์ด๋ฆ„์ด ์ž๋™์œผ๋กœ ์ƒ์„ฑ๋จ
    • ์˜ˆ: imgCon โ†’ InputFild_imgCon__3h9Ks์ฒ˜๋Ÿผ ๋ณ€๊ฒฝ
  • ๊ฐ™์€ ์ด๋ฆ„์„ ๋‹ค๋ฅธ ์ปดํฌ๋„ŒํŠธ์—์„œ ์จ๋„ ์ถฉ๋Œ ์—†์Œ
  • ๊ธ€๋กœ๋ฒŒ ์Šคํƒ€์ผ์ด๋‚˜ Styled-components์ฒ˜๋Ÿผ ๋ณ„๋„ ์„ค์ •์ด ํ•„์š” ์—†์Œ

์–ด๋–ค ์Šคํƒ€์ผ ๋ฐฉ๋ฒ•์„ ์„ ํƒํ• ๊นŒ?

๋ฐฉ๋ฒ•ํŠน์ง• ๋ฐ ์ถ”์ฒœ ์ƒํ™ฉ
์ „์—ญ CSS์•ฑ ์ „์ฒด์— ์ ์šฉ๋˜๋Š” ๋ฆฌ์…‹, ํฐํŠธ, ์ƒ‰์ƒ ๋“ฑ ๊ณตํ†ต ์Šคํƒ€์ผ์šฉ
CSS Modules์ปดํฌ๋„ŒํŠธ๋ณ„ ์Šคํƒ€์ผ๋ง์ด ํ•„์š”ํ•˜์ง€๋งŒ ๋ณ„๋„ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ์—†์ด ์‚ฌ์šฉํ•˜๊ณ  ์‹ถ์„ ๋•Œ
Styled-components๋™์  ์Šคํƒ€์ผ๋ง์ด ๋งŽ๊ฑฐ๋‚˜ ์ปดํฌ๋„ŒํŠธ์™€ ์Šคํƒ€์ผ์„ ๋ฐ€์ ‘ํ•˜๊ฒŒ ์—ฐ๊ฒฐํ•˜๊ณ  ์‹ถ์„ ๋•Œ

์‹ค์Šต ํ™”๋ฉด

์ด๋ฏธ์ง€ hover์‹œ, ์ œ๋ชฉ, ์•„ํ‹ฐ์ŠคํŠธ๋ช… ๋‚˜์˜ด


๐Ÿ”ธ useState

  • useState๋Š” ์ปดํฌ๋„ŒํŠธ์— ์ƒํƒœ๋ฅผ ์ถ”๊ฐ€ํ•˜๋Š” Hook
  • ํ™”๋ฉด์— ๋ณด์—ฌ์ฃผ๋Š” ๋ฐ์ดํ„ฐ๋ฅผ ์ €์žฅํ•˜๊ณ  ๋ณ€๊ฒฝํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•ด์ฃผ๋Š” ๊ธฐ๋Šฅ

๊ธฐ๋ณธ ์‚ฌ์šฉ๋ฒ•

1
const [state, setState] = useState(์ดˆ๊ธฐ๊ฐ’);
  • state: ํ˜„์žฌ ์ƒํƒœ ๊ฐ’
  • setState: ์ƒํƒœ๋ฅผ ์—…๋ฐ์ดํŠธํ•˜๋Š” ํ•จ์ˆ˜
  • ์ดˆ๊ธฐ๊ฐ’: ์ฒ˜์Œ ๋ Œ๋”๋ง ์‹œ ์‚ฌ์šฉํ•  ๊ฐ’

ํ•ต์‹ฌ ํŠน์ง•

1. ์ƒํƒœ ์—…๋ฐ์ดํŠธ

์ƒํƒœ๋ฅผ ์—…๋ฐ์ดํŠธํ•˜๋ฉด ์ปดํฌ๋„ŒํŠธ๊ฐ€ ์ž๋™์œผ๋กœ ๋‹ค์‹œ ๋ Œ๋”๋ง๋œ๋‹ค.

1
2
setState(์ƒˆ๋กœ์šด๊ฐ’); // ์ง์ ‘ ๊ฐ’ ์ „๋‹ฌ
setState(prevState => prevState + 1); // ์ด์ „ ์ƒํƒœ ๊ธฐ๋ฐ˜ ์—…๋ฐ์ดํŠธ
1
2
3
4
5
6
7
8
9
10
11
function ์ƒํ’ˆ์นด๋“œ() {
  const [์ˆ˜๋Ÿ‰, ์ˆ˜๋Ÿ‰๋ณ€๊ฒฝ] = useState(1);
  
  return (
    <div>
      <p>์„ ํƒ ์ˆ˜๋Ÿ‰: {์ˆ˜๋Ÿ‰}๊ฐœ</p>
      <button onClick={() => ์ˆ˜๋Ÿ‰๋ณ€๊ฒฝ(์ˆ˜๋Ÿ‰ + 1)}>์ถ”๊ฐ€</button>
      <button onClick={() => ์ˆ˜๋Ÿ‰๋ณ€๊ฒฝ(์ˆ˜๋Ÿ‰ - 1)}>๊ฐ์†Œ</button>
    </div>
  );
}

2. ์ค‘์š”ํ•œ ๊ทœ์น™

  • Hook์€ ์ปดํฌ๋„ŒํŠธ ์ตœ์ƒ์œ„ ๋ ˆ๋ฒจ์—์„œ๋งŒ ํ˜ธ์ถœ
  • ์กฐ๊ฑด๋ฌธ, ๋ฐ˜๋ณต๋ฌธ, ์ด๋ฒคํŠธ ํ•ธ๋“ค๋Ÿฌ ์•ˆ์—์„œ ์ง์ ‘ ํ˜ธ์ถœ X
  • ๋Œ€์‹ , ์ด๋ฒคํŠธ ํ•ธ๋“ค๋Ÿฌ์—์„œ๋Š” ์ฝœ๋ฐฑ ์•ˆ์—์„œ setState๋Š” ํ˜ธ์ถœ ๊ฐ€๋Šฅ
1
2
3
4
5
6
7
8
9
10
// โŒ ์ž˜๋ชป๋œ ์‚ฌ์šฉ
if (์กฐ๊ฑด) {
  const [x, setX] = useState(0);
}

// โœ… ์˜ฌ๋ฐ”๋ฅธ ์‚ฌ์šฉ
const [x, setX] = useState(0);
if (์กฐ๊ฑด) {
  setX(5);
}

3. ๊ฐ์ฒด์™€ ๋ฐฐ์—ด ์ƒํƒœ

์ƒํƒœ๋กœ ๊ฐ์ฒด๋‚˜ ๋ฐฐ์—ด์„ ๋‹ค๋ฃฐ ๋•Œ๋Š” ๋ถˆ๋ณ€์„ฑ(immutability) ์„ ์ง€์ผœ์•ผ ํ•œ๋‹ค.
์ฆ‰, ๊ธฐ์กด ๊ฐ’์„ ์ง์ ‘ ์ˆ˜์ •ํ•˜์ง€ ๋ง๊ณ , ๋ณต์‚ฌ ํ›„ ๋ณ€๊ฒฝํ•˜๋Š” ๋ฐฉ์‹์œผ๋กœ ์—…๋ฐ์ดํŠธํ•ด์•ผ ํ•จ

1
2
3
4
5
6
7
8
9
10
11
// โŒ ์ž˜๋ชป๋œ ๋ฐฉ๋ฒ• (์ง์ ‘ ์ˆ˜์ •)
form.name = '๊น€์ฒ ์ˆ˜';

// โœ… ์˜ฌ๋ฐ”๋ฅธ ๋ฐฉ๋ฒ• (๋ณต์‚ฌ ํ›„ ๋ณ€๊ฒฝ)
setForm({ ...form, name: '๊น€์ฒ ์ˆ˜' });

// โœ… ๋ฐฐ์—ด์— ํ•ญ๋ชฉ ์ถ”๊ฐ€
setItems([...items, ์ƒˆํ•ญ๋ชฉ]);

// โœ… ๋ฐฐ์—ด์—์„œ ํ•ญ๋ชฉ ์ œ๊ฑฐ
setItems(items.filter(item => item.id !== ์‚ญ์ œํ• ID));

์˜ˆ์ œ: ํšŒ์›๊ฐ€์ž… ํผ

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
function ํšŒ์›๊ฐ€์ž…ํผ() {
  const [ํšŒ์›์ •๋ณด, ํšŒ์›์ •๋ณด๋ณ€๊ฒฝ] = useState({
    ์•„์ด๋””: '',
    ๋น„๋ฐ€๋ฒˆํ˜ธ: '',
    ์ด๋ฉ”์ผ: '',
    ์ „ํ™”๋ฒˆํ˜ธ: ''
  });
  
  const ์ž…๋ ฅ๋ณ€๊ฒฝ = (e) => {
    // ๊ธฐ์กด ๊ฐ์ฒด ๋ณต์‚ฌ ํ›„ ํŠน์ • ์†์„ฑ๋งŒ ๋ณ€๊ฒฝ
    ํšŒ์›์ •๋ณด๋ณ€๊ฒฝ({
      ...ํšŒ์›์ •๋ณด,
      [e.target.name]: e.target.value
    });
  };
  
  return (
    <form>
      <input 
        name="์•„์ด๋””" 
        value={ํšŒ์›์ •๋ณด.์•„์ด๋””} 
        onChange={์ž…๋ ฅ๋ณ€๊ฒฝ} 
      />
      <input 
        name="์ด๋ฉ”์ผ" 
        value={ํšŒ์›์ •๋ณด.์ด๋ฉ”์ผ} 
        onChange={์ž…๋ ฅ๋ณ€๊ฒฝ} 
      />
    </form>
  );
}

5. ์ƒํƒœ ์—…๋ฐ์ดํŠธ ํŠน์„ฑ

  1. ๋น„๋™๊ธฐ์ 
    1
    2
    
    setCount(count + 1);
    console.log(count); // ๋ฐ”๋กœ ๋ฐ˜์˜๋˜์ง€ ์•Š์Œ
    

    setState ํ˜ธ์ถœ ์งํ›„ ์ƒํƒœ๊ฐ€ ์ฆ‰์‹œ ๋ณ€๊ฒฝ๋˜๋Š”๊ฒŒ ์•„๋‹ˆ๋ผ, ๋‹ค์Œ ๋ Œ๋”๋ง ๋•Œ ์ ์šฉ๋ผ.

  2. ์ผ๊ด„ ์ฒ˜๋ฆฌ(Batching) React๋Š” ์—ฌ๋Ÿฌ ์ƒํƒœ ์—…๋ฐ์ดํŠธ๋ฅผ ํ•œ ๋ฒˆ์— ์ฒ˜๋ฆฌํ•จ. ๊ทธ๋ž˜์„œ ์—ฌ๋Ÿฌ ๋ฒˆ ์—ฐ์† ํ˜ธ์ถœํ•ด๋„ ์ตœ์‹  ์ƒํƒœ๋ฅผ ๊ธฐ์ค€์œผ๋กœ ๋™์ž‘ํ•˜์ง€ ์•Š์„ ์ˆ˜ ์žˆ์Œ.

  3. ์ด์ „ ์ƒํƒœ ๊ธฐ๋ฐ˜ ์—…๋ฐ์ดํŠธ ์ด์ „ ์ƒํƒœ๋ฅผ ๊ธฐ๋ฐ˜์œผ๋กœ ์—…๋ฐ์ดํŠธํ•  ๋•Œ๋Š” ํ•จ์ˆ˜ ํ˜•ํƒœ๋ฅผ ์‚ฌ์šฉ
    1
    
    setCount(prev => prev + 1);
    

์ž์ฃผ ํ•˜๋Š” ์‹ค์ˆ˜

1. ์ƒํƒœ ์—…๋ฐ์ดํŠธ ํ›„ ์ด์ „ ๊ฐ’ ์ถœ๋ ฅ

1
2
3
4
function ํด๋ฆญํ•ธ๋“ค๋Ÿฌ() {
  set๊ฐœ์ˆ˜(๊ฐœ์ˆ˜ + 1);
  console.log(๊ฐœ์ˆ˜); // ์—ฌ์ „ํžˆ ์ด์ „ ๊ฐ’ ์ถœ๋ ฅ
}

-> ์ƒํƒœ ์—…๋ฐ์ดํŠธ๋Š” ๋น„๋™๊ธฐ์ ์œผ๋กœ ์ฒ˜๋ฆฌ๋˜์–ด ์ฆ‰์‹œ ๋ฐ˜์˜๋˜์ง€ ์•Š์Œ

2. ๊ฐ์ฒด/๋ฐฐ์—ด ๋ณ€๊ฒฝ์ด ํ™”๋ฉด์— ๋ฐ˜์˜๋˜์ง€ ์•Š์Œ

1
2
3
4
5
6
7
8
9
10
11
12
// ์ž˜๋ชป๋œ ๋ฐฉ๋ฒ•
const ํ•ญ๋ชฉ๋“ค = [...ํ• ์ผ๋ชฉ๋ก];
ํ•ญ๋ชฉ๋“ค[0].์™„๋ฃŒ = true;
setํ• ์ผ๋ชฉ๋ก(ํ•ญ๋ชฉ๋“ค); // ์ฐธ์กฐ๊ฐ€ ๊ฐ™์•„ ๋ณ€๊ฒฝ ๊ฐ์ง€ ์•ˆ๋จ -> ๊ฐ์ฒด ํƒ€์ž…

// ์˜ฌ๋ฐ”๋ฅธ ๋ฐฉ๋ฒ•
setํ• ์ผ๋ชฉ๋ก(์ด์ „๋ชฉ๋ก =>
  ์ด์ „๋ชฉ๋ก.map((ํ•ญ๋ชฉ, ์ธ๋ฑ์Šค) =>
    ์ธ๋ฑ์Šค === 0 ? {...ํ•ญ๋ชฉ, ์™„๋ฃŒ: true} : ํ•ญ๋ชฉ
  )
);

3. โ€œToo many re-rendersโ€ ์˜ค๋ฅ˜

1
2
3
4
5
6
// ์ž˜๋ชป๋œ ๋ฐฉ๋ฒ•
return <button onClick={ํ•ธ๋“ค๋Ÿฌ()}>ํด๋ฆญ</button> // โŒ

// ์˜ฌ๋ฐ”๋ฅธ ๋ฐฉ๋ฒ•
return <button onClick={ํ•ธ๋“ค๋Ÿฌ}>ํด๋ฆญ</button> // โœ…
return <button onClick={() => ํ•ธ๋“ค๋Ÿฌ()}>ํด๋ฆญ</button> // โœ…

์œ ์šฉ tip

์ดˆ๊ธฐ ์ƒํƒœ๋ฅผ ๊ณ„์‚ฐํ•˜๋Š” ํ•จ์ˆ˜ ์‚ฌ์šฉ

๋ฌด๊ฑฐ์šด ๊ณ„์‚ฐ์ด ํ•„์š”ํ•œ ์ดˆ๊ธฐ๊ฐ’์€ ํ•จ์ˆ˜๋กœ ์ „๋‹ฌํ•˜๋ฉด ์ฒซ ๋ Œ๋”๋ง์—๋งŒ ์‹คํ–‰๋ฉ๋‹ˆ๋‹ค.

1
2
3
4
5
// ๋งค ๋ Œ๋”๋ง๋งˆ๋‹ค ์‹คํ–‰ (๋น„ํšจ์œจ์ )
const [items, setItems] = useState(createExpensiveList()); // โŒ

// ์ดˆ๊ธฐํ™” ์‹œ์—๋งŒ ํ•œ ๋ฒˆ ์‹คํ–‰ (ํšจ์œจ์ )
const [items, setItems] = useState(() => createExpensiveList()); // โœ…

key๋ฅผ ์‚ฌ์šฉํ•œ ์ƒํƒœ ์ดˆ๊ธฐํ™”

์ปดํฌ๋„ŒํŠธ์— ๋‹ค๋ฅธ key๋ฅผ ์ „๋‹ฌํ•˜๋ฉด React๋Š” ์ปดํฌ๋„ŒํŠธ๋ฅผ ์ƒˆ๋กœ ์ƒ์„ฑํ•˜๊ณ  ์ƒํƒœ๋ฅผ ์ดˆ๊ธฐํ™”ํ•ฉ๋‹ˆ๋‹ค.

1
2
3
4
5
6
7
8
9
10
11
12
function ์•ฑ() {
  const [์‚ฌ์šฉ์žID, ์‚ฌ์šฉ์žID๋ณ€๊ฒฝ] = useState(1);
  
  return (
    <>
      <button onClick={() => ์‚ฌ์šฉ์žID๋ณ€๊ฒฝ(์‚ฌ์šฉ์žID + 1)}>
        ๋‹ค์Œ ์‚ฌ์šฉ์ž
      </button>
      <ํ”„๋กœํ•„ key={์‚ฌ์šฉ์žID} /> {/* key๊ฐ€ ๋ณ€๊ฒฝ๋˜๋ฉด ์ƒํƒœ ์ดˆ๊ธฐํ™” */}
    </>
  );
}

๐Ÿ”ธ ๋ฐฐ์—ด๊ณผ ํ•จ๊ป˜ ์‚ฌ์šฉํ•˜๋Š” ๊ณ ์ฐจํ•จ์ˆ˜

๊ณ ์ฐจํ•จ์ˆ˜(Higher Order Functions)๋Š” ๋‹ค๋ฅธ ํ•จ์ˆ˜๋ฅผ ์ธ์ž๋กœ ๋ฐ›๊ฑฐ๋‚˜ ํ•จ์ˆ˜๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋Š” ํ•จ์ˆ˜

1. map() - ๋ฐฐ์—ด์˜ ๋ชจ๋“  ์š”์†Œ๋ฅผ ๋ณ€ํ™˜ํ•˜์—ฌ ์ƒˆ ๋ฐฐ์—ด ๋ฐ˜ํ™˜

1
2
3
4
5
6
7
8
9
10
11
12
13
// ์ˆซ์ž ๋ฐฐ์—ด์˜ ๊ฐ ์š”์†Œ๋ฅผ 2๋ฐฐ๋กœ ๋งŒ๋“ค๊ธฐ
const numbers = [1, 2, 3, 4, 5];
const doubled = numbers.map(num => num * 2);
console.log(doubled); // [2, 4, 6, 8, 10]

// ๊ฐ์ฒด ๋ฐฐ์—ด์—์„œ ํŠน์ • ์†์„ฑ๋งŒ ์ถ”์ถœํ•˜๊ธฐ
const users = [
  { id: 1, name: '๊น€์ฒ ์ˆ˜', age: 25 },
  { id: 2, name: '์ด์˜ํฌ', age: 30 },
  { id: 3, name: '๋ฐ•๋ฏผ์ˆ˜', age: 28 }
];
const names = users.map(user => user.name);
console.log(names); // ['๊น€์ฒ ์ˆ˜', '์ด์˜ํฌ', '๋ฐ•๋ฏผ์ˆ˜']

2. filter() - ์กฐ๊ฑด์— ๋งž๋Š” ์š”์†Œ๋งŒ ํฌํ•จํ•˜๋Š” ์ƒˆ ๋ฐฐ์—ด ๋ฐ˜ํ™˜

1
2
3
4
5
6
7
8
9
10
11
12
13
// ์ง์ˆ˜๋งŒ ํ•„ํ„ฐ๋งํ•˜๊ธฐ
const numbers = [1, 2, 3, 4, 5, 6];
const evens = numbers.filter(num => num % 2 === 0);
console.log(evens); // [2, 4, 6]

// ํŠน์ • ๋‚˜์ด ์ด์ƒ์ธ ์‚ฌ์šฉ์ž๋งŒ ํ•„ํ„ฐ๋งํ•˜๊ธฐ
const users = [
  { name: '๊น€์ฒ ์ˆ˜', age: 25 },
  { name: '์ด์˜ํฌ', age: 30 },
  { name: '๋ฐ•๋ฏผ์ˆ˜', age: 18 }
];
const adults = users.filter(user => user.age >= 20);
console.log(adults); // [{ name: '๊น€์ฒ ์ˆ˜', age: 25 }, { name: '์ด์˜ํฌ', age: 30 }]

3. reduce() - ๋ฐฐ์—ด์˜ ์š”์†Œ๋ฅผ ํ•˜๋‚˜์˜ ๊ฐ’์œผ๋กœ ์ค„์ด๊ธฐ

1
2
3
4
5
6
7
8
9
10
11
12
13
// ๋ฐฐ์—ด ์š”์†Œ์˜ ํ•ฉ๊ณ„ ๊ตฌํ•˜๊ธฐ
const numbers = [1, 2, 3, 4, 5];
const sum = numbers.reduce((accumulator, current) => accumulator + current, 0);
console.log(sum); // 15

// ๊ฐ์ฒด ๋ฐฐ์—ด์˜ ํŠน์ • ์†์„ฑ ํ•ฉ๊ณ„ ๊ตฌํ•˜๊ธฐ
const cart = [
  { item: '๋…ธํŠธ๋ถ', price: 1200000 },
  { item: '๋งˆ์šฐ์Šค', price: 35000 },
  { item: 'ํ‚ค๋ณด๋“œ', price: 45000 }
];
const totalPrice = cart.reduce((total, product) => total + product.price, 0);
console.log(totalPrice); // 1280000

4. forEach() - ๋ฐฐ์—ด์˜ ๊ฐ ์š”์†Œ์— ๋Œ€ํ•ด ํ•จ์ˆ˜ ์‹คํ–‰

1
2
3
4
5
6
7
8
9
10
11
12
13
// ๋ฐฐ์—ด์˜ ๊ฐ ์š”์†Œ ์ถœ๋ ฅํ•˜๊ธฐ
const fruits = ['์‚ฌ๊ณผ', '๋ฐ”๋‚˜๋‚˜', '์˜ค๋ Œ์ง€'];
fruits.forEach(fruit => console.log(fruit));
// ์‚ฌ๊ณผ
// ๋ฐ”๋‚˜๋‚˜
// ์˜ค๋ Œ์ง€

// ๋ฐฐ์—ด ์š”์†Œ์˜ ํ•ฉ๊ณ„ ๊ณ„์‚ฐํ•˜๊ธฐ (๋ถ€์ˆ˜ ํšจ๊ณผ ์‚ฌ์šฉ)
let total = 0;
[1, 2, 3, 4].forEach(num => {
  total += num;
});
console.log(total); // 10

5. find() - ์กฐ๊ฑด์„ ๋งŒ์กฑํ•˜๋Š” ์ฒซ ๋ฒˆ์งธ ์š”์†Œ ๋ฐ˜ํ™˜

1
2
3
4
5
6
7
8
// ํŠน์ • ID๋ฅผ ๊ฐ€์ง„ ์‚ฌ์šฉ์ž ์ฐพ๊ธฐ
const users = [
  { id: 1, name: '๊น€์ฒ ์ˆ˜' },
  { id: 2, name: '์ด์˜ํฌ' },
  { id: 3, name: '๋ฐ•๋ฏผ์ˆ˜' }
];
const user = users.find(user => user.id === 2);
console.log(user); // { id: 2, name: '์ด์˜ํฌ' }

6. some() - ํ•˜๋‚˜๋ผ๋„ ์กฐ๊ฑด์„ ๋งŒ์กฑํ•˜๋ฉด true ๋ฐ˜ํ™˜

1
2
3
4
// ๋ฐฐ์—ด์— ์Œ์ˆ˜๊ฐ€ ์žˆ๋Š”์ง€ ํ™•์ธ
const numbers = [1, 2, 3, -1, 4];
const hasNegative = numbers.some(num => num < 0);
console.log(hasNegative); // true

7. every() - ๋ชจ๋“  ์š”์†Œ๊ฐ€ ์กฐ๊ฑด์„ ๋งŒ์กฑํ•˜๋ฉด true ๋ฐ˜ํ™˜

1
2
3
4
5
6
7
8
// ๋ชจ๋“  ์‚ฌ์šฉ์ž๊ฐ€ ์„ฑ์ธ์ธ์ง€ ํ™•์ธ
const users = [
  { name: '๊น€์ฒ ์ˆ˜', age: 25 },
  { name: '์ด์˜ํฌ', age: 30 },
  { name: '๋ฐ•๋ฏผ์ˆ˜', age: 18 }
];
const allAdults = users.every(user => user.age >= 20);
console.log(allAdults); // false

8. flatMap() - map() ํ›„ ๊ฒฐ๊ณผ๋ฅผ 1๋ ˆ๋ฒจ ํ‰ํƒ„ํ™”

1
2
3
4
// ๋ฌธ์žฅ์„ ๋‹จ์–ด ๋ฐฐ์—ด๋กœ ๋ณ€ํ™˜
const sentences = ['Hello world', 'I love JavaScript'];
const words = sentences.flatMap(sentence => sentence.split(' '));
console.log(words); // ['Hello', 'world', 'I', 'love', 'JavaScript']

9. sort() - ๋ฐฐ์—ด ์š”์†Œ ์ •๋ ฌ

1
2
3
4
5
6
7
8
9
10
11
12
const numbers = [3, 1, 4, 1, 5];
numbers.sort((a, b) => a - b);
console.log(numbers); // [1, 1, 3, 4, 5]

// ๊ฐ์ฒด ๋ฐฐ์—ด ์ •๋ ฌ
const users = [
  { name: '๊น€์ฒ ์ˆ˜', age: 25 },
  { name: '์ด์˜ํฌ', age: 30 },
  { name: '๋ฐ•๋ฏผ์ˆ˜', age: 18 }
];
users.sort((a, b) => a.age - b.age);
console.log(users); // ๋‚˜์ด์ˆœ์œผ๋กœ ์ •๋ ฌ๋จ

10. findIndex() - ์กฐ๊ฑด์„ ๋งŒ์กฑํ•˜๋Š” ์ฒซ ๋ฒˆ์งธ ์š”์†Œ์˜ ์ธ๋ฑ์Šค ๋ฐ˜ํ™˜

1
2
3
const fruits = ['์‚ฌ๊ณผ', '๋ฐ”๋‚˜๋‚˜', '์˜ค๋ Œ์ง€', 'ํฌ๋„'];
const index = fruits.findIndex(fruit => fruit === '์˜ค๋ Œ์ง€');
console.log(index); // 2

11. flat() - ์ค‘์ฒฉ ๋ฐฐ์—ด์„ ํ‰ํƒ„ํ™”

1
2
3
const nestedArray = [1, [2, 3], [4, [5, 6]]];
const flattened = nestedArray.flat(2); // ๊นŠ์ด 2๊นŒ์ง€ ํ‰ํƒ„ํ™”
console.log(flattened); // [1, 2, 3, 4, 5, 6]

12. reduceRight() - ์˜ค๋ฅธ์ชฝ์—์„œ ์™ผ์ชฝ์œผ๋กœ reduce ์‹คํ–‰

1
2
3
const array = ['a', 'b', 'c', 'd'];
const result = array.reduceRight((acc, curr) => acc + curr);
console.log(result); // 'dcba'

13. at() - ์–‘์ˆ˜ ๋˜๋Š” ์Œ์ˆ˜ ์ธ๋ฑ์Šค๋กœ ์š”์†Œ์— ์ ‘๊ทผ (ES2022)

1
2
3
const array = [5, 12, 8, 130, 44];
console.log(array.at(2)); // 8
console.log(array.at(-1)); // 44 (๋งˆ์ง€๋ง‰ ์š”์†Œ)

14. Array.from() - ์œ ์‚ฌ ๋ฐฐ์—ด ๊ฐ์ฒด๋‚˜ ์ดํ„ฐ๋Ÿฌ๋ธ”์„ ๋ฐฐ์—ด๋กœ ๋ณ€ํ™˜

1
2
3
4
5
// ๋ฌธ์ž์—ด์˜ ๊ฐ ๋ฌธ์ž๋ฅผ ๋ฐฐ์—ด๋กœ ๋ณ€ํ™˜
console.log(Array.from('hello')); // ['h', 'e', 'l', 'l', 'o']

// ๋งคํ•‘ ํ•จ์ˆ˜ ์‚ฌ์šฉ (๋‘ ๋ฒˆ์งธ ์ธ์ž)
console.log(Array.from([1, 2, 3], x => x * 2)); // [2, 4, 6]

15. Array.of() - ์ฃผ์–ด์ง„ ์ธ์ž๋กœ ์ƒˆ ๋ฐฐ์—ด ์ƒ์„ฑ

1
2
console.log(Array.of(1, 2, 3)); // [1, 2, 3]
console.log(Array.of('a', 'b', 'c')); // ['a', 'b', 'c']

16. entries(), keys(), values() - ๋ฐฐ์—ด์˜ ๋ฐ˜๋ณต์ž ๋ฉ”์„œ๋“œ

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
const array = ['a', 'b', 'c'];

// entries() - [์ธ๋ฑ์Šค, ๊ฐ’] ์Œ์˜ ๋ฐ˜๋ณต์ž ๋ฐ˜ํ™˜
for (const [index, element] of array.entries()) {
  console.log(index, element);
}

// keys() - ์ธ๋ฑ์Šค ๋ฐ˜ํ™˜
for (const index of array.keys()) {
  console.log(index);
}

// values() - ๊ฐ’ ๋ฐ˜ํ™˜
for (const element of array.values()) {
  console.log(element);
}

๐Ÿ”ธ ๋ณต์Šต

โœ… array, object state ๋ณ€๊ฒฝ ์‹œ ์ฃผ์˜์‚ฌํ•ญ

๐Ÿ’ก React์—์„œ ๋ฐฐ์—ด๊ณผ ๊ฐ์ฒด๋Š” ๋ถˆ๋ณ€์„ฑ์„ ์ง€ํ‚ค๋ฉฐ ์ƒํƒœ๋ฅผ ์—…๋ฐ์ดํŠธํ•ด์•ผ ํ•จ (์›๋ณธ ์ง์ ‘ ์ˆ˜์ • โŒ)

๋ฐฐ์—ด(Array) ์ƒํƒœ ๋ณ€๊ฒฝ

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
const addTodo = (newTodo) => {
  setTodos([...todos, newTodo]);
  // ์Šคํ”„๋ ˆ๋“œ ์—ฐ์‚ฐ์ž(...)๋กœ ๊ธฐ์กด ๋ฐฐ์—ด์„ ๋ณต์‚ฌํ•˜๊ณ  ์ƒˆ ํ•ญ๋ชฉ ์ถ”๊ฐ€
};

// 2. ๋ฐฐ์—ด์—์„œ ํ•ญ๋ชฉ ์ œ๊ฑฐํ•˜๊ธฐ
const removeTodo = (index) => {
  setTodos(todos.filter((_, i) => i !== index));
  // filter๋กœ ํ•ด๋‹น ์ธ๋ฑ์Šค๋ฅผ ์ œ์™ธํ•œ ์ƒˆ ๋ฐฐ์—ด ์ƒ์„ฑ
};

// 3. ๋ฐฐ์—ด์˜ ํŠน์ • ํ•ญ๋ชฉ ์ˆ˜์ •ํ•˜๊ธฐ
const updateTodo = (index, newText) => {
  setTodos(todos.map((todo, i) => i === index ? newText : todo));
  // map์œผ๋กœ ํŠน์ • ์ธ๋ฑ์Šค์˜ ํ•ญ๋ชฉ๋งŒ ์ƒˆ ๊ฐ’์œผ๋กœ ๋ณ€๊ฒฝ
};

๊ฐ์ฒด(Object) ์ƒํƒœ ๋ณ€๊ฒฝ

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
const [user, setUser] = useState({
  name: 'ํ™๊ธธ๋™',
  age: 30,
  email: 'hong@example.com'
});

// 1. ๊ฐ์ฒด์˜ ํŠน์ • ์†์„ฑ ๋ณ€๊ฒฝํ•˜๊ธฐ
const updateEmail = (newEmail) => {
  setUser({
    ...user,  // ๊ธฐ์กด ๊ฐ์ฒด์˜ ๋ชจ๋“  ์†์„ฑ์„ ๋ณต์‚ฌ
    email: newEmail  // ๋ณ€๊ฒฝํ•  ์†์„ฑ๋งŒ ๋ฎ์–ด์“ฐ๊ธฐ
  });
};

// 2. ์ค‘์ฒฉ๋œ ๊ฐ์ฒด ์†์„ฑ ๋ณ€๊ฒฝํ•˜๊ธฐ
const [product, setProduct] = useState({
  name: '๋…ธํŠธ๋ถ',
  specs: {
    cpu: 'i7',
    ram: '16GB',
    storage: '512GB'
  }
});

const upgradeRam = (newRam) => {
  setProduct({
    ...product,
    specs: {
      ...product.specs,  // ์ค‘์ฒฉ ๊ฐ์ฒด๋„ ๋ณต์‚ฌ
      ram: newRam  // ๋ณ€๊ฒฝํ•  ์†์„ฑ๋งŒ ๋ฎ์–ด์“ฐ๊ธฐ
    }
  });
};

๋ฐฐ์—ด ์† ๊ฐ์ฒด ๋ณ€๊ฒฝํ•˜๊ธฐ

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
const [students, setStudents] = useState([
  { id: 1, name: '๊น€์ฒ ์ˆ˜', grade: 'A' },
  { id: 2, name: '์ด์˜ํฌ', grade: 'B' },
  { id: 3, name: '๋ฐ•๋ฏผ์ˆ˜', grade: 'C' }
]);

// ํŠน์ • ํ•™์ƒ์˜ ์„ฑ์  ๋ณ€๊ฒฝํ•˜๊ธฐ
const updateGrade = (id, newGrade) => {
  setStudents(
    students.map(student =>
      student.id === id
        ? { ...student, grade: newGrade }
        : student
    )
  );
};
  • ๋ถˆ๋ณ€์„ฑ์„ ์ง€ํ‚ค๋ฉด React๊ฐ€ ๋ณ€๊ฒฝ ์‚ฌํ•ญ์„ ๊ฐ์ง€ํ•˜๊ณ  ํšจ์œจ์ ์œผ๋กœ ๋ Œ๋”๋งํ•จ
  • ์ค‘์ฒฉ ๊ตฌ์กฐ๊ฐ€ ๋ณต์žกํ•ด์ง€๋ฉด immer ๊ฐ™์€ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ์ถ”์ฒœ

โœ… Props ์ „์†ก

๊ธฐ๋ณธ ๊ฐœ๋…

  • Props๋Š” ๋ถ€๋ชจ โ†’ ์ž์‹์œผ๋กœ ๋ฐ์ดํ„ฐ ์ „๋‹ฌ ๋ฐฉ์‹
  • ๋งˆ์น˜ ํ•จ์ˆ˜์˜ ์ธ์ž์ฒ˜๋Ÿผ ์ž‘๋™ํ•˜๋ฉฐ ์ฝ๊ธฐ ์ „์šฉ

๊ธฐ๋ณธ ์ „๋‹ฌ ์˜ˆ์‹œ

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// ๋ถ€๋ชจ ์ปดํฌ๋„ŒํŠธ
function ParentComponent() {
  const userName = "ํ™๊ธธ๋™";
  const userAge = 30;

  return (
    <ChildComponent name={userName} age={userAge} />
  );
  }

// ์ž์‹ ์ปดํฌ๋„ŒํŠธ
function ChildComponent(props) {
  return (
    <div>
      <h2>์ด๋ฆ„: {props.name}</h2>
      <p>๋‚˜์ด: {props.age}์„ธ</p>
    </div>
  );
}

Props ์ „์†ก ํŒจํ„ด

1. ๊ตฌ์กฐ ๋ถ„ํ•ด ํ• ๋‹น

1
2
3
4
5
6
7
8
9
// ๋” ๊น”๋”ํ•œ ๊ตฌ์กฐ ๋ถ„ํ•ด ํ• ๋‹น ๋ฐฉ์‹
function ProfileCard({ name, age, isVerified = false }) {
return (
  <div className="profile-card">
    <h2>{name} {isVerified && 'โœ“'}</h2>
    <p>๋‚˜์ด: {age}์„ธ</p>
  </div>
);
}

2. children prop ํ™œ์šฉ

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
function Card({ title, children }) {
  return (
    <div className="card">
      <h2 className="card-title">{title}</h2>
      <div className="card-content">
        {children}
      </div>
    </div>
  );
}

// ์‚ฌ์šฉ ์˜ˆ์‹œ
function App() {
  return (
    <Card title="ํšŒ์› ์ •๋ณด">
      <p>์ด ์นด๋“œ์—๋Š” ์–ด๋–ค ๋‚ด์šฉ์ด๋“  ๋„ฃ์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.</p>
      <button>์ˆ˜์ •ํ•˜๊ธฐ</button>
    </Card>
  );
}

3. ๊ฐ์ฒด ํ˜•ํƒœ๋กœ props ์ „๋‹ฌ

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
function UserProfile() {
  const userDetails = {
    name: "๊น€์ฒ ์ˆ˜",
    age: 28,
    email: "kim@example.com",
    role: "๊ฐœ๋ฐœ์ž"
  };

  return <ProfileDetails {...userDetails} />;
}

function ProfileDetails({ name, age, email, role }) {
  return (
    <div className="profile">
      <h2>{name}</h2>
      <ul>
        <li>๋‚˜์ด: {age}</li>
        <li>์ด๋ฉ”์ผ: {email}</li>
        <li>์ง์—…: {role}</li>
      </ul>
    </div>
  );
}

๋‚ด์šฉ์„ ์ข€ ๋” ๊ตฌ์ฒด์ ์œผ๋กœ ์•Œ๊ณ  ์‹ถ์–ด์„œ ์ž์„ธํ•œ props์— ๋Œ€ํ•ด์„œ๋Š” ๋”ฐ๋กœ ํฌ์ŠคํŒ…ํ–ˆ๋‹ค !
[CS] Props?


1
2
3
4
5
6
7
8
๊ณต๋ถ€ ๋ฐฉ๋ฒ•
- useEffect : ์˜๋ฌธ ๋ฒ„์ „ docs ๋ณด๋ฉด์„œ ๊ณต๋ถ€ํ•˜๋ฉด ์ข‹์Œ
- ์„ฑ๋Šฅ ํ–ฅ์ƒ์— ํ•„์š”ํ•œ ํ›… : useCallback, useMemo

์ฐธ๊ณ  docs
[๋ชจ๋˜ JS ํŠœํ† ๋ฆฌ์–ผ - ์ฝ”์–ด ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ](https://ko.javascript.info/)
๋˜๋Š”
๋ชจ๋˜ ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ์ฑ… ์—ด๋ฒˆ๋ณด๊ธฐ ~

๐Ÿ”ธ ์˜๋ฌธ์ : setCount(count + 1)๋Š” ๋ถˆ๋ณ€์„ฑ์„ ์ง€ํ‚ค๋Š”๊ฐ€?

Q.

useState์—์„œ setCount(count + 1)์™€ ๊ฐ™์€ ๋ฐฉ์‹์€ ์ง์ ‘ ๊ฐ’์„ ๋ณ€๊ฒฝํ•˜๋Š” ๊ฒƒ์ฒ˜๋Ÿผ ๋ณด์ด๋Š”๋ฐ, ์ด์ฒ˜๋Ÿผ ์ง์ ‘ ๊ฐ’ ๋ณ€๊ฒฝ์ด ํ—ˆ์šฉ๋˜๋Š” ๊ฒฝ์šฐ์™€ ๋ถˆ๋ณ€์„ฑ์„ ๋ฐ˜๋“œ์‹œ ์ง€์ผœ์•ผ ํ•˜๋Š” ๊ฒฝ์šฐ์˜ ์ฐจ์ด์ ์€?


โœ… A.

์š”์ ์„ ๋จผ์ € ๋ง์”€๋“œ๋ฆฌ๋ฉด ๋ถˆ๋ณ€์„ฑ์„ ๊นจ๋Š” ๋ชจ๋“  ์—…๋ฐ์ดํŠธ๋Š” ์ง€์–‘ํ•ฉ๋‹ˆ๋‹ค. ๊ฒ‰๋ณด๊ธฐ์—” count๋ฅผ ์ง์ ‘ ์ˆ˜์ •ํ•˜๋Š” ๊ฒƒ์ฒ˜๋Ÿผ ๋ณด์—ฌ๋„, ์‹ค์ œ๋กœ๋Š” ์ƒˆ๋กœ์šด ๊ฐ’์„ ๋งŒ๋“ค์–ด์„œ React์—๊ฒŒ ์ „๋‹ฌํ•˜๋Š” ๊ฒƒ์ด๊ธฐ ๋•Œ๋ฌธ์— ๋ถˆ๋ณ€์„ฑ์„ ์ง€ํ‚ต๋‹ˆ๋‹ค.

ํ•ต์‹ฌ ๊ฐœ๋… ์š”์•ฝ

  • count + 1์€ ์ƒˆ๋กœ์šด ์ˆซ์ž ๊ฐ’์„ ๊ณ„์‚ฐํ•ฉ๋‹ˆ๋‹ค (์›์‹œ ํƒ€์ž… โ†’ ๊ฐ’ ์ž์ฒด ๋ณต์‚ฌ๋จ)
  • setCount()๋Š” ์ด ์ƒˆ ๊ฐ’์„ React์—๊ฒŒ ์ „๋‹ฌํ•˜์—ฌ ์ƒํƒœ๋ฅผ ์—…๋ฐ์ดํŠธํ•˜๋„๋ก ์š”์ฒญํ•ฉ๋‹ˆ๋‹ค
  • React๋Š” ๋‚ด๋ถ€์ ์œผ๋กœ ์ด์ „ ๊ฐ’๊ณผ ๋น„๊ต ํ›„, ํ•„์š” ์‹œ ๋ฆฌ๋ Œ๋”๋ง

์ˆซ์ž, ๋ฌธ์ž์—ด, boolean๊ณผ ๊ฐ™์€ ์›์‹œ ํƒ€์ž…(primitive types)์€ ๊ฐ’ ์ž์ฒด๊ฐ€ ์ €์žฅ๋˜๋ฏ€๋กœ, ์ƒˆ ๊ฐ’์„ ๊ณ„์‚ฐํ•  ๋•Œ ์ž๋™์œผ๋กœ ๋ถˆ๋ณ€์„ฑ์ด ์œ ์ง€๋ฉ๋‹ˆ๋‹ค.

๐Ÿ”Ž ์›์‹œ ํƒ€์ž… vs ์ฐธ์กฐ ํƒ€์ž… ์ฐจ์ด

ํƒ€์ž…๋ถˆ๋ณ€์„ฑ ์œ ์ง€ ์—ฌ๋ถ€์˜ˆ์‹œ
์›์‹œ ํƒ€์ž…์ž๋™ ์œ ์ง€setCount(count + 1)
์ฐธ์กฐ ํƒ€์ž…์ง์ ‘ ์œ ์ง€ ํ•„์š”setUser({ ...user, name: 'ํ™๊ธธ๋™' })
  • ์›์‹œ ํƒ€์ž…: ์ˆซ์ž, ๋ฌธ์ž์—ด, boolean โ†’ ๊ฐ’์„ ๋ฐ”๋กœ ์ˆ˜์ •ํ•ด๋„ ์ž๋™ ๋ถˆ๋ณ€์„ฑ ์œ ์ง€
  • ์ฐธ์กฐ ํƒ€์ž…: ๊ฐ์ฒด, ๋ฐฐ์—ด โ†’ ์ง์ ‘ ๋ณต์‚ฌ(...) ํ›„ ์ˆ˜์ •ํ•ด์•ผ ์•ˆ์ „

END

This post is licensed under CC BY 4.0 by the author.