๐ŸŽ‰ berenickt ๋ธ”๋กœ๊ทธ์— ์˜จ ๊ฑธ ํ™˜์˜ํ•ฉ๋‹ˆ๋‹ค. ๐ŸŽ‰
Front
08-map-key

1. Lists

1.1 JS map()

for ๋ฐ˜๋ณต๋ฌธ์€ JSX ์ค‘๊ด„ํ˜ธ ์•ˆ์—์„œ ์‚ฌ์šฉํ•  ์ˆ˜ ์—†์–ด์„œ map()์„ ๋Œ€์‹  ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค. ๋ชจ๋“  array ์ž๋ฃŒ ์šฐ์ธก์—” map() ํ•จ์ˆ˜๋ฅผ ๋ถ™์ผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

1.1.1 ๋ฐฐ์—ด ์š”์†Œ๋งŒํผ ๋ฐ˜๋ณต์‹คํ–‰

1
let array = [2, 3, 4]
2
3
array.map(() => {
4
console.log(1) // 1์ด 3๋ฒˆ ์ถœ๋ ฅ
5
})

1.1.2 ์ฝœ๋ฐฑํ•จ์ˆ˜

์ฝœ๋ฐฑํ•จ์ˆ˜์— ํŒŒ๋ผ๋ฏธํ„ฐ ์•„๋ฌด๋ ‡๊ฒŒ๋‚˜ ์ž‘๋ช…ํ•˜๋ฉด, ๊ทธ ํŒŒ๋ผ๋ฏธํ„ฐ๋Š” array ์•ˆ์— ์žˆ๋˜ ๋ชจ๋“  ์ž๋ฃŒ๋ฅผ ํ•˜๋‚˜์”ฉ ์ถœ๋ ฅํ•ด์ค๋‹ˆ๋‹ค. (๊ทธ๋ƒฅ ์†Œ๊ด„ํ˜ธ์•ˆ์— ์žˆ๋Š” ํ•จ์ˆ˜๋ฅผ ์ฝœ๋ฐฑํ•จ์ˆ˜๋ผ๊ณ  ํ•ฉ๋‹ˆ๋‹ค).

1
let array = [2, 3, 4]
2
3
array.map(Element => {
4
console.log(Element) // 2, 3, 4
5
})

1.1.3 ์š”์†Œ ์กฐ์ž‘ํ•ด ์ƒˆ ๋ฐฐ์—ด๋กœ

1
let array = [2, 3, 4]
2
3
let newArray = array.map(Element => {
4
return Element * 10
5
})
6
console.log(newArray) // [20, 30, 40]

1.2 Rendering Multiple Components

  • Rendering Multiple Components = ๋‹ค์ˆ˜ ์ปดํฌ๋„ŒํŠธ ๋ Œ๋”๋ง
1
const numbers = [1, 2, 3, 4, 5]
2
const listItems = numbers.map(numbers => <li>{numbers}</li>)
3
4
// ์ „์ฒด listItems ๋ฐฐ์—ด์„ <ul> ์š”์†Œ ์•ˆ์— ์‚ฝ์ž…ํ•œ ๋’ค DOM์—์„œ ๋ Œ๋”๋ง
5
const root = ReactDOM.createRoot(document.getElementById('root'))
6
root.render(<ul>{listItems}</ul>) // 1๋ถ€ํ„ฐ 5๊นŒ์ง€์˜ ์ˆซ์ž๋กœ ์ด๋ฃจ์–ด์ง„ ๋ฆฌ์ŠคํŠธ

1.3 Basic List Component

๋ณดํ†ต ๋ฆฌ์ŠคํŠธ๋ฅผ ์ปดํฌ๋„ŒํŠธ ์•ˆ์—์„œ ๋ Œ๋”๋งํ•ฉ๋‹ˆ๋‹ค. ์œ„ ์ฝ”๋“œ์˜ numbers ๋ฐฐ์—ด์„ ๋ฐ›์•„์„œ ์ˆœ์„œ์—†๋Š” ๋ชฉ๋ก์„ ์ถœ๋ ฅํ•˜๋Š” ์ปดํฌ๋„ŒํŠธ๋กœ ๋ฆฌํŒฉํ† ๋งํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

1
function NumberList(props) {
2
const numbers = props.numbers
3
const listItems = numbers.map(number => <li key={number.toString()}>{number}</li>)
4
return <ul>{listItems}</ul>
5
}
6
7
const numbers = [1, 2, 3, 4, 5]
8
9
const root = ReactDOM.createRoot(document.getElementById('root'))
10
root.render(<NumberList numbers={numbers} />)

์ด ์ฝ”๋“œ๋ฅผ ์‹คํ–‰ํ•˜๋ฉด, ๋ฆฌ์ŠคํŠธ ์•„์ดํ…œ์— ํ‚ค๋ฅผ ๋„ฃ์–ด์•ผํ•œ๋‹ค๋Š” ๊ฒฝ๊ณ ๊ฐ€ ํ‘œ์‹œ๋ฉ๋‹ˆ๋‹ค. ํ‚ค(key)๋Š” ์š”์†Œ ๋ฆฌ์ŠคํŠธ๋ฅผ ๋งŒ๋“ค ๋•Œ ํฌํ•จํ•ด์•ผํ•˜๋Š” ํŠน์ˆ˜ํ•œ ๋ฌธ์ž์—ด ์†์„ฑ์ž…๋‹ˆ๋‹ค.


2. Key

  • key = ์–ด๋–ค ์•„์ดํ…œ์ธ์ง€ ์ธ์‹ํ•˜๋Š” ํŒ๋ณ„ํ•˜๋Š” ID
    • key ๊ฐ’์€ ๊ณ ์œ ํ•ด์•ผ ํ•จ
  • key ๊ฐ’์€ html์„ ๋žœ๋”๋ง ํ•  ๋•Œ, ๋ณ€๊ฒฝ๋œ html๋งŒ ๋žœ๋”๋ง, ์ตœ์ ํ™” ํ•˜๊ธฐ ์œ„ํ•ด ์‚ฌ์šฉ

ํ‚ค๋ฅผ ์„ ํƒํ•˜๋Š” ๊ฐ€์žฅ ์ข‹์€ ๋ฐฉ๋ฒ•์€ ๋ฆฌ์ŠคํŠธ ์•„์ดํ…œ์˜ ํ˜•์ œ ์ค‘ ๋ฆฌ์ŠคํŠธ ์•„์ดํ…œ์„ ๊ณ ์œ ํ•˜๊ฒŒ ์‹๋ณ„ํ•  ์ˆ˜ ์žˆ๋Š” ๋ฌธ์ž์—ด์„ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๋Œ€๋ถ€๋ถ„์˜ ๊ฒฝ์šฐ ๋ฐ์ดํ„ฐ์˜ ID๋ฅผ ํ‚ค๋กœ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.

์•„์ดํ…œ์˜ ์ˆœ์„œ๊ฐ€ ๋ฐ”๋€” ์ˆ˜ ์žˆ๋Š” ๊ฒฝ์šฐ ํ‚ค์— ์ธ๋ฑ์Šค๋ฅผ ์‚ฌ์šฉํ•˜์ง€ ์•Š๋Š” ๊ฒŒ ์ข‹์Šต๋‹ˆ๋‹ค. ์ด๋กœ ์ธํ•ด ์„ฑ๋Šฅ์ด ์ €ํ•˜๋˜๊ฑฐ๋‚˜ ์ปดํฌ๋„ŒํŠธ์˜ state์— ๋”ฐ๋ฅธ ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค


2.1 key๋กœ ์ปดํฌ๋„ŒํŠธ ์ถ”์ถœ

key๋Š” ์ฃผ๋ณ€ ๋ฐฐ์—ด์˜ ์ปจํ…์ŠคํŠธ์—์„œ๋งŒ ์˜๋ฏธ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค.

์˜ˆ๋ฅผ ๋“ค์–ด, ListItem ์ปดํฌ๋„ŒํŠธ๋ฅผ์ถ”์ถœํ•œ ๊ฒฝ์šฐ, ListItem ์ž์ฒด์˜ ๋ฃจํŠธ <li> ์š”์†Œ๊ฐ€ ์•„๋‹Œ ๋ฐฐ์—ด์˜ <ListItem /> ์š”์†Œ๊ฐ€ ํ‚ค๋ฅผ ๊ฐ€์ง€๊ณ  ์žˆ์–ด์•ผํ•ฉ๋‹ˆ๋‹ค.

1
function ListItem(props) {
2
// Correct! There is no need to specify the key here:
3
return <li>{props.value}</li>
4
}
5
6
function NumberList(props) {
7
const numbers = props.numbers
8
const listItems = numbers.map(number => (
9
// Correct! Key should be specified inside the array.
10
<ListItem key={number.toString()} value={number} />
11
))
12
return <ul>{listItems}</ul>
13
}
14
15
const numbers = [1, 2, 3, 4, 5]
16
17
const root = ReactDOM.createRoot(document.getElementById('root'))
18
root.render(<NumberList numbers={numbers} />)

2.2 JSX์—์„œ map() ํฌํ•จํ•˜๋Š” ๋ฒ•

JSX๋Š” ์ค‘๊ด„ํ˜ธ๋ฅผ ์ด์šฉํ•˜๋ฉด ๋ชจ๋“  ํ‘œํ˜„์‹์„ ํฌํ•จํ•  ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์— map() ๋„ ์ธ๋ผ์ธ์œผ๋กœ ํฌํ•จ์‹œํ‚ฌ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

1
function ListItem(props) {
2
return <li>{props.value}</li>
3
}
4
5
function NumberList(props) {
6
const numbers = props.numbers
7
// ์ค‘๊ด‘ํ˜ธ๋ฅผ ์ด์šฉํ•ด map() ๋„ฃ์„ ์ˆ˜ ์žˆ์Œ
8
return (
9
<ul>
10
{numbers.map(number => (
11
<ListItem key={number.toString()} value={number} />
12
))}
13
</ul>
14
)
15
}
16
17
const numbers = [1, 2, 3, 4, 5]
18
19
const root = ReactDOM.createRoot(document.getElementById('root'))
20
root.render(<NumberList numbers={numbers} />)

๋•Œ๋กœ๋Š” ์ฝ”๋“œ๊ฐ€ ๋” ๋ช…ํ™•ํ•ด์งˆ ์ˆ˜๋„ ์žˆ์ง€๋งŒ ์ด ์Šคํƒ€์ผ๋„ ์•…์šฉ๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. JS์™€ ๋งˆ์ฐฌ๊ฐ€์ง€๋กœ ๊ฐ€๋…์„ฑ์„ ์œ„ํ•ด ๋ณ€์ˆ˜๋กœ ์ถ”์ถœํ•ด์•ผํ•  ์ง€์— ๋Œ€ํ•œ๊ฑด ๊ฐœ๋ฐœ์ž๊ฐ€ ํŒ๋‹จํ•ด์•ผํ•ฉ๋‹ˆ๋‹ค. map() ๋ฐ”๋””๊ฐ€ ๋„ˆ๋ฌด ์ค‘์ฒฉ๋˜์–ด์žˆ๋‹ค๋ฉด, ์ปดํฌ๋„ŒํŠธ๋กœ ์ถ”์ถœ ํ•˜๋Š” ๊ฒƒ์ด ์ข‹์Šต๋‹ˆ๋‹ค.


3. ์˜ˆ์ œ

1
import { useState } from 'react'
2
3
export default function App() {
4
const [inputValue, setInputValue] = useState('')
5
const [list, setList] = useState(['๋ฐฅ๋จน๊ธฐ', '์ฝ”๋”ฉํ•˜๊ธฐ'])
6
7
const addTodoList = () => {
8
setList(prevList => {
9
return [inputValue, ...prevList]
10
})
11
setInputValue('')
12
}
13
14
return (
15
<>
16
<input type="text" value={inputValue} onChange={e => setInputValue(e.target.value)} />
17
<button onClick={addTodoList}>์ถ”๊ฐ€</button>
18
<ul>
19
{list.map(item => {
20
return <li>{item}</li>
21
})}
22
</ul>
23
</>
24
)
25
}

์ฝ˜์†” ์ฐฝ์„ ๋ณด๋ฉด, key๊ฐ€ ์—†๋‹ค๊ณ  Warning ์ฐฝ์ด ๋‚˜์˜ด

  • ๋ฟ๋งŒ ์•„๋‹ˆ๋ผ, Elementsํƒญ์„ ํ‚จ ์ฑ„๋กœ ๊ฐ’์„ ์ถ”๊ฐ€ํ•ด๋ณด๋ฉด, ๋ชจ๋“  DOM li ์š”์†Œ๊ฐ€ ํ•œ๋ฒˆ์— ์—…๋ฐ์ดํŠธ๋จ
  • ์™œ๋ƒํ•˜๋ฉด key๊ฐ’์ด ์—†์–ด์„œ, React๋Š” ์–ด๋–ค ํ•ญ๋ชฉ์ด ์—…๋ฐ์ดํŠธ๋๋Š”์ง€ ๋ชฐ๋ผ์„œ, ๋ชจ๋“  ํ•ญ๋ชฉ์„ ์—…๋ฐ์ดํŠธํ•ด์คŒ
  • ๋งŒ์•ฝ ํ•ญ๋ชฉ์ด 100๋งŒ๊ฐœ ์žˆ๋‹ค๋ฉด, ์ƒˆ ํ•ญ๋ชฉ์„ ์ถ”๊ฐ€ํ•  ๋–„๋งˆ๋‹ค 100๋งŒ๊ฐœ๋ฅผ ์—…๋ฐ์ดํŠธํ•ด์คŒ (๋น„ํšจ์œจ์ )
1
export default function App() {
2
// ์ƒ๋žต
3
return (
4
<>
5
<input type="text" value={inputValue} onChange={e => setInputValue(e.target.value)} />
6
<button onClick={addTodoList}>์ถ”๊ฐ€</button>
7
<ul>
8
{list.map(item => {
9
// key๊ฐ’์ด ์—†์œผ๋ฉด ๊ฒฝ๊ณ ๊ฐ€ ๋œฌ๋‹ค. key๊ฐ’์€ ๊ณ ์œ ํ•œ ๊ฐ’์ด์–ด์•ผ ํ•˜๊ณ , index๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ์•ˆ๋œ๋‹ค.
10
// ์ด์ œ ์ „์ฒด ํ•ญ๋ชฉ์„ ์—…๋ฐ์ดํŠธํ•˜๋Š” ๊ฒƒ์ด ์•„๋‹ˆ๋ผ, ํŠน์ • key๊ฐ’์˜ ํ•ญ๋ชฉ๋งŒ ์ถ”๊ฐ€ํ•œ๋‹ค.
11
return <li key={item}>{item}</li>
12
})}
13
</ul>
14
</>
15
)
16
}

key๊ฐ’์„ ์ถ”๊ฐ€ํ•ด์ฃผ๋ฉด, ํ•ญ๋ชฉ์„ ์ถ”๊ฐ€ํ•  ๋•Œ, ์ „์ฒด ํ•ญ๋ชฉ์„ ์—…๋ฐ์ดํŠธํ•˜๋Š” ๊ฒƒ์ด ์•„๋‹ˆ๋ผ, ํŠน์ • key๊ฐ’์˜ ํ•ญ๋ชฉ๋งŒ ์ถ”๊ฐ€ํ•œ๋‹ค.


3.1 key๊ฐ’์œผ๋กœ index๋ฅผ ์‚ฌ์šฉXโญ

1
export default function App() {
2
// ์ƒ๋žต
3
return (
4
<>
5
<input type="text" value={inputValue} onChange={e => setInputValue(e.target.value)} />
6
<button onClick={addTodoList}>์ถ”๊ฐ€</button>
7
<ul>
8
{list.map((item, index) => {
9
// key๊ฐ’์ด ์—†์œผ๋ฉด ๊ฒฝ๊ณ ๊ฐ€ ๋œฌ๋‹ค. key๊ฐ’์€ ๊ณ ์œ ํ•œ ๊ฐ’์ด์–ด์•ผ ํ•˜๊ณ , index๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ์•ˆ๋œ๋‹ค.
10
// index๋Š” ์•ˆ์ •์ (๊ณ ์ •์ )์ด์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์—, ์ƒˆ ํ•ญ๋ชฉ์„ ์ถ”๊ฐ€ํ•˜๋ฉด, index ์ˆœ์„œ๊ฐ€ ์ถ”๊ฐ€ํ•œ ๋งŒํผ ๋ฐ€๋ฆผ
11
// ๊ทธ๋ž˜์„œ React๋Š” key๊ฐ’์ด ๊ณ ์ •์ ์ด์ง€ ์•Š๋‹ค๊ณ  ํŒ๋‹จํ•ด์„œ, ์ƒˆ ํ•ญ๋ชฉ์„ ์ถ”๊ฐ€ํ•˜๋ฉด, ์ „์ฒด ํ•ญ๋ชฉ์„ ์—…๋ฐ์ดํŠธํ•จ
12
return <li key={index}>{item}</li>
13
})}
14
</ul>
15
</>
16
)
17
}

์ถ”๊ฐ€์ ์œผ๋กœ key๊ฐ’์œผ๋กœ index๋ฅผ ์“ฐ๋ฉด ์•ˆ๋ฉ๋‹ˆ๋‹ค. ์™œ๋ƒํ•˜๋ฉด index๋Š” ์•ˆ์ •์ (๊ณ ์ •์ )์ด์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์—, ์ƒˆ ํ•ญ๋ชฉ์„ ์ถ”๊ฐ€ํ•˜๋ฉด, index ์ˆœ์„œ๊ฐ€ ์ถ”๊ฐ€ํ•œ ๋งŒํผ ๋ฐ€๋ฆฌ๊ฒŒ ๋ฉ๋‹ˆ๋‹ค. ๊ทธ๋ž˜์„œ React๋Š” key๊ฐ’์ด ๊ณ ์ •์ ์ด์ง€ ์•Š๋‹ค๊ณ  ํŒ๋‹จํ•ด์„œ, ์ƒˆ ํ•ญ๋ชฉ์„ ์ถ”๊ฐ€ํ•˜๋ฉด, ์ „์ฒด ํ•ญ๋ชฉ์„ ์—…๋ฐ์ดํŠธํ•ฉ๋‹ˆ๋‹ค.


3.2 key๊ฐ’์€ ๊ณ ์œ ํ•ด์•ผ ํ•จ

1
import { useState } from 'react'
2
3
export default function App() {
4
const [inputValue, setInputValue] = useState('')
5
const [list, setList] = useState([
6
{
7
id: '1',
8
value: '๋ฐฅ๋จน๊ธฐ',
9
},
10
{
11
id: '2',
12
value: '์ฝ”๋”ฉํ•˜๊ธฐ',
13
},
14
])
15
16
const addTodoList = () => {
17
setList(prevList => {
18
return [
19
{
20
id: list.length + 1 + '',
21
value: inputValue,
22
},
23
...prevList,
24
]
25
})
26
setInputValue('')
27
}
28
29
return (
30
<>
31
<input type="text" value={inputValue} onChange={e => setInputValue(e.target.value)} />
32
<button onClick={addTodoList}>์ถ”๊ฐ€</button>
33
<ul>
34
{list.map(item => {
35
return <li key={item.id}>{item.value}</li>
36
})}
37
</ul>
38
</>
39
)
40
}

[์ฐธ๊ณ ] ๊ณต์‹๋ฌธ์„œ