[๋ฆฌ์กํธ๋ฅผ ๋ค๋ฃจ๋ ๊ธฐ์ ] 6์ฅ - ์ปดํฌ๋ํธ ๋ฐ๋ณต
์ด ๊ธ์ ๊น๋ฏผ์ค(velopert)๋์ ๋ฆฌ์กํธ๋ฅผ ๋ค๋ฃจ๋ ๊ธฐ์ ์์ฐธ์กฐํ์ฌ ์์ฑํ ๊ธ์ ๋๋ค.
์น ์ ํ๋ฆฌ์ผ์ด์ ์ ๋ง๋ค๋ค ๋ณด๋ฉด ๋ฐ๋ณต๋๋ ์ฝ๋๋ฅผ ์์ฑํ ๋๊ฐ ์๋ค. ์ด ์ฅ์์๋ ๋ฆฌ์กํธ ํ๋ก์ ํธ์์ ๋ฐ๋ณต์ ์ธ ์ ์ฉ์ ํจ์จ์ ์ผ๋ก ๋ณด์ฌ์ฃผ๊ณ ๊ด๋ฆฌํ๋ ๋ฐฉ๋ฒ์ ์์๋ณธ๋ค.
map()
ํจ์#
์๋ฐ์คํฌ๋ฆฝํธ ๋ฐฐ์ด์ ์๋ฐ์คํฌ๋ฆฝํธ ๋ฐฐ์ด ๊ฐ์ฒด์ ๋ด์ฅ ํจ์์ธ map()
ํจ์๋ฅผ ์ฌ์ฉํ์ฌ ๋ฐ๋ณต๋๋ ์ปดํฌ๋ํธ๋ฅผ๋ ๋๋งํ ์ ์๋ค.
๋จผ์ map()
ํจ์์ ๋ํ mdn ๋ฌธ์๋ฅผ ๋ณด๊ณ ์ ๋ฆฌํด๋ณธ๋ค
map()
๋ฉ์๋๋ ๋ฐฐ์ด ๋ด์ ๋ชจ๋ ์์ ๊ฐ๊ฐ์ ๋ํ์ฌ ์ฃผ์ด์ง ํจ์๋ฅผ ํธ์ถํ ๊ฒฐ๊ณผ๋ฅผ๋ชจ์ ์๋ก์ด ๋ฐฐ์ด์ ๋ฐํํ๋ ํจ์์ด๋ค.
arr.map(callback(currentValue[, index[, array]])[, thisArg])
map()
ํจ์๋ callback
ํจ์, thisArg
(์ต์
๋) ๋ฅผ ๋งค๊ฐ๋ณ์๋ก ๋ฐ๋๋ค. ๊ทธ๋ฆฌ๊ณ callback
ํจ์๋ currentValue
, index
(์ต์
๋), array
(์ต์
๋) 3๊ฐ์ ๋งค๊ฐ๋ณ์๋ฅผ ๋ฐ๋๋ค
callback
currentValue
: ํ์ฌ ์ฒ๋ฆฌํ๊ณ ์๋ ์์index
(์ต์ ๋) : ํ์ฌ ์ฒ๋ฆฌํ๊ณ ์๋ ์์์ index ๊ฐarray
(์ต์ ๋) : ํ์ฌ ์ฒ๋ฆฌํ๊ณ ์๋ ์๋ณธ ๋ฐฐ์ด
thisArg
(์ต์ ๋) : callback ํจ์ ๋ด๋ถ์์ ์ฌ์ฉํ this ๋ ํผ๋ฐ์ค
๊ทธ๋ฆฌ๊ณ ๋ฐฐ์ด์ ๊ฐ ์์์ ๋ํด ์คํํ callback
์ ๊ฒฐ๊ณผ๋ฅผ ๋ชจ์ ์๋ก์ด ๋ฐฐ์ด์ ๋ฆฌํดํ๋ค.
#
์์ var numbers = [1, 4, 9];var doubles = numbers.map(function (num) { return num * 2;});// doubles = [2, 8, 18]
var roots = numbers.map(Math.sqrt); // Math.sqrt๋ x์ ์ ๊ณฑ๊ทผ์ ๋ฐํํ๋ ํจ์.// roots = [1, 2, 3]
call()
์ด๋ apply()
๋ฉ์๋๋ฅผ ์ด์ฉํ์ฌ ์ ์ฌ ๋ฐฐ์ด ๊ฐ์ฒด์ ๋ฐฐ์ด ๋ฉ์๋๋ฅผ ๋น๋ ค์์ฌ์ฉํ ์ ์๋ค.
let map = Array.prototype.map;let a = map.call('Hello World', function (x) { return x.charCodeAt(0); // ๊ฐ ๋ฌธ์์ ASCII ์ธ์ฝ๋ฉ ๊ฐ์ ๊ฐ์ ธ์ค๋ ํจ์.});// a = [72, 101, 108, 108, 111, 32, 87, 111, 114, 108, 100]
var elems = document.querySelectorAll('select option:checked');var values = [].map.call(elems, function (obj) { return obj.value;});
Array.from()
์ ์ฌ์ฉํ ์๋ ์๋ค.
map
์ ํ๋์ ์ธ์๋ง ๋ฐ๋ ์ฝ๋ฐฑ์ ์ฌ์ฉํ๋ ๊ฒฝ์ฐ๊ฐ ๋ง์๋ฐ, ๋ ๊ฐ ์ด์์ ์ธ์๋ฅผ์ฌ์ฉํ๋ ํจ์๋ฅผ ์ฌ์ฉํ ๋ ํผ๋์ค๋ฌ์ธ ์ ์๋ค.
['1', '2', '3'].map(parseInt);
์ด๋ ๊ฒ ์์ฑํ์ ๋ ๊ฒฐ๊ณผ๋ฅผ [1, 2, 3]
์ผ๋ก ๊ธฐ๋ํ์ง๋ง ๊ฒฐ๊ณผ๋ [1, NaN, NaN]
์ธ๋ฐ, ์ด๋ parseInt
ํจ์๊ฐ ๋ ๊ฐ์ ์ธ์๋ฅผ ๋ฐ์ ์ ์๊ธฐ ๋๋ฌธ์ด๋ค. ์ฒซ ๋ฒ์งธ ์ธ์๋๋ณํํ๊ณ ์ ํ๋ ํํ์ด๊ณ , ๋ ๋ฒ์งธ๋ ์ซ์๋ก ๋ณํํ ๋ ์ฌ์ฉํ ์ง๋ฒ(radix)์ด๋ค.
Array.prototype.map
์ ์์์ ๋ณธ ๊ฒ์ฒ๋ผ ๋ฐฐ์ด์ ๊ฐ, ์ธ๋ฑ์ค, ๋ฐฐ์ด ์ธ ๊ฐ์ง์ ์ธ์๋ฅผ ์ ๋ฌํ๋ฏ๋ก, ๋ฐฐ์ด์ ์ธ๋ฑ์ค๊ฐ ์ง๋ฒ(radix)์ผ๋ก ์ ๋ฌ๋์ด ํผ๋์ค๋ฝ๊ฒ ์๋ํ๋ค.
[1, NaN, NaN]
์ผ๋ก ํ์๋๋ ์ด์ ๋ ์๋์ ๋งํฌ๋ก parseInt()
ํจ์๋ฅผ ์ดํดํด์ผํ๋ค.
#
๋ฐ์ดํฐ ๋ฐฐ์ด์ ์ปดํฌ๋ํธ ๋ฐฐ์ด๋ก ๋ณํํ๊ธฐ๊ธฐ์กด ์๋ฐ์คํฌ๋ฆฝํธ์ ๋ฐฐ์ด๋ก ์ปดํฌ๋ํธ๋ก ๊ตฌ์ฑ๋ ๋ฐฐ์ด์ ์์ฑํ ์ ์๋ค. src ๋๋ ํ ๋ฆฌ์ IterationSample.js
ํ์ผ์ ์์ฑํ๋ค.
IterationSample.js
import React from 'react';
const IterationSample = () => { const names = ['๋์ฌ๋', '์ผ์', '๋', '๋ฐ๋']; const nameList = names.map((name) => <li>{name}</li>); return <ul>{nameList}</ul>;};
export default IterationSample;
nameList
์ <li>๋์ฌ๋</li>
, <li>์ผ์</li>
, ... ์ ์ปดํฌ๋ํธ๋ก ๊ตฌ์ฑ๋ ๋ฐฐ์ด์ด ์ ์ฅ๋๋ค.
์ด์ App ์ปดํฌ๋ํธ์์ ๋ถ๋ฌ์ ๋ ๋๋ง ํด๋ณด๋ฉด
App.js
import React, {Component} from 'react';import IterationSample from './IterationSample';
class App extends Component { render() { return <IterationSample />; }}
export default App;
์ํ๋ ๋๋ก ๋ ๋๋ง์ด ๋ ๊ฒ์ ํ์ธํ ์ ์๋ค.
ํ์ง๋ง F12
ํค๋ฅผ ๋๋ฌ ํฌ๋กฌ์ ์ฝ์ ์ฐฝ์ ํ์ธํด ๋ณด๋ฉด ๊ฒฝ๊ณ ๋ฉ์์ง๊ฐ ๋ํ๋๋ ๊ฒ์๋ณผ ์ ์๋ค.
๊ฒฝ๊ณ ๋ฉ์์ง๋ฅผ ๋ณด๋ฉด ๋ฆฌ์คํธ์ ์๋ ๊ฐ ์์ ์์(child)๊ฐ "key" prop์ด ์๋ค๊ณ ๋์จ๋ค.
key๊ฐ ๋ฌด์์ธ์ง ์์๋ณด์.
#
key๋ฆฌ์กํธ์์ key๋ ์ปดํฌ๋ํธ ๋ฐฐ์ด์ ๋ ๋๋ง ํ์ ๋, ์ด๋ค ์์์ ๋ณ๋์ด ์์๋์ง ์๋ณํ๋ ๊ฒ์ ๋๋๋ฐ ์ฌ์ฉ๋๋ ์์ฑ์ด๋ค. key๊ฐ ์์ ๋๋ Virtual DOM์ ๋น๊ตํ๋ฉด์๋ฆฌ์คํธ๋ฅผ ์์ฐจ์ ์ผ๋ก ๋น๊ตํ๋ฉด์ ๋ณํ๋ฅผ ๊ฐ์งํ๊ธฐ ๋๋ฌธ์, ๋ฆฌ์คํธ์ ๋งจ ์์ด๋ ์ค๊ฐ์ ์๋ฆฌ๋จผํธ๊ฐ ์ฝ์ ๋ ๋ ์ฑ๋ฅ ์ ํ๊ฐ ๋ฐ์ํ๋ค. ๋ฐ๋ผ์ ์ด ๋ฌธ์ ๋ฅผ ๊ทน๋ณตํ๊ธฐ ์ํด key ๋ฅผ ์ฌ์ฉํ๋ค.
์ฑ๋ฅ ์ ํ๊ฐ ๋ฐ์ํ๋ ์์ธ์ ์๋์ ๋งํฌ์์ ์์ธํ ์ค๋ช ํด์ฃผ๊ณ ์๋ค.
์ฌ์กฐ์ (Reconciliation) - React
#
key ์ค์ key ๊ฐ์ ์ค์ ํ ๋๋ map ํจ์์ ์ธ์๋ก ์ ๋ฌ๋๋ ํจ์ ๋ด๋ถ์์ ์ปดํฌ๋ํธ props
๋ฅผ ์ค์ ํ๋ฏ์ด ์ค์ ํ๋ฉด ๋๋ค. ๊ทธ๋ฐ๋ฐ key ๊ฐ์ ์ธ์ ๋ ์ ์ผํด์ผ ํ๋ค. ๋ฐ๋ผ์ ๋ฐ์ดํฐ๊ฐ ๊ฐ์ง ๊ณ ์ณ๊ฐ์ key ๊ฐ์ผ๋ก ์ค์ ํด์ผ ํ๋ค.
์์ ๋ง๋ ์์ ์ปดํฌ๋ํธ์๋ ๊ณ ์ ๋ฒํธ๊ฐ ์๊ธฐ ๋๋ฌธ์ ์ฝ๋ฐฑ ํจ์์ ์ธ์์ธ index ๊ฐ์ ์ฌ์ฉํ ์ ์๋ค.
IterationSample.js
import React from 'react';
const IterationSample = () => { const names = ['๋์ฌ๋', '์ผ์', '๋', '๋ฐ๋']; const nameList = names.map((name, index) => <li key={index}>{name}</li>); return <ul>{nameList}</ul>;};
export default IterationSample;
์ด์ ๊ฐ ํญ๋ชฉ์ ๊ณ ์ ํ key๋ฅผ ์ง์ ํด ์ฃผ์๊ธฐ ๋๋ฌธ์ ๊ฐ๋ฐ์ ๋๊ตฌ์์ ๊ฒฝ๊ณ ๋ฉ์์ง๋ฅผํ์ํ์ง ์๋ ๊ฒ์ ํ์ธํ ์ ์๋ค.
ํ์ง๋ง ํญ๋ชฉ์ ์์๊ฐ ๋ฐ๋ ์ ์๋ ๊ฒฝ์ฐ key์ index๋ฅผ ์ฌ์ฉํ๋ ๊ฒ์ ๊ถ์ฅํ์ง ์๋๋ค. ๋ ๋๋งํ ํญ๋ชฉ์ ๋ํ ์์ ์ ์ธ ID๊ฐ ์์ ๋, ์ตํ์ ์๋จ์ผ๋ก index๋ฅผ key ๋ก ์ฌ์ฉํ๋ค.
์ธ๋ฑ์ค๋ฅผ key๋ก ์ฌ์ฉํ ๊ฒฝ์ฐ ๋ถ์ ์ ์ธ ์ํฅ์ ๋ํ ์์ธ ์ค๋ช ์ ์๋์ ๋งํฌ๋ฅผ ์ฐธ์กฐํ์.
Index as a key is an anti-pattern
#
์์ฉ์ด์ ๊ณ ์ ๋ ๋ฐฐ์ด์ด ์๋ ๋์ ์ธ ๋ฐฐ์ด์ ๋ ๋๋งํ๋๋ก ํ๋ค. ์ฆ ๋ฐ์ดํฐ๋ฅผ ์ถ๊ฐํ๊ณ ์ญ์ ํ๋ ๊ฒ์ด ๊ฐ๋ฅํ๋๋ก ์์ ๋ฅผ ๋ณ๊ฒฝํด๋ณธ๋ค. ๋ํ index ๊ฐ์ด ์๋ ๊ณ ์ณ๊ฐ์ ๋ง๋ค์ด key๋ก ์ฌ์ฉํ๋ ๋ฒ๋ ์์๋ณธ๋ค.
#
์ด๊ธฐ ์ํ ์ค์ ํ๊ธฐIterationSample
์ปดํฌ๋ํธ์์ useState
๋ฅผ ์ฌ์ฉํ์ฌ ์ํ๋ฅผ ์ค์ ํ๋ค.
import React, {useState} from 'react';
const IterationSample = () => { const [names, setNames] = useState([ {id: 1, text: '๋์ฌ๋'}, {id: 2, text: '์ผ์'}, {id: 3, text: '๋'}, {id: 4, text: '๋ฐ๋'}, ]); const [inputText, setInputText] = useState(''); const [nextId, setNextId] = useState(5);
const nameList = names.map((name) => <li key={name.id}>{name.text}</li>); return <ul>{nameList}</ul>;};
export default IterationSample;
์ด์ ๊ณผ ๋ฌ๋ฆฌ names
์ text
์ ๊ณ ์ ์ id
๋ฅผ ๋ด๊ณ ์๋ ๊ฐ์ฒด๋ค์ ๋ฐฐ์ด์ ๋ฃ์ด์ค๋ค. ๊ทธ๋ฆฌ๊ณ ์๋ก ์ถ๊ฐํ ๋ฐ์ดํฐ๋ฅผ ์
๋ ฅ๋ฐ๊ธฐ ์ํด inputText
๋ฅผ ์ถ๊ฐํ๊ณ , nextId
๋ฅผ ํตํด ์ถ๊ฐ๋ ๋ฐ์ดํฐ์ ์์ด๋๋ฅผ ๊ณ์ฐํด ์ฃผ๋๋ก ํ๋ค.
#
์ถ๊ฐ ๊ธฐ๋ฅ ๊ตฌํํ๊ธฐimport React, {useState} from 'react';
const IterationSample = () => { const [names, setNames] = useState([ {id: 1, text: '๋์ฌ๋'}, {id: 2, text: '์ผ์'}, {id: 3, text: '๋'}, {id: 4, text: '๋ฐ๋'}, ]); const [inputText, setInputText] = useState(''); const [nextId, setNextId] = useState(5);
const onChange = (e) => setInputText(e.target.value); const onClick = () => { const nextNames = names.concat({ id: nextId, text: inputText, }); setNextId(nextId + 1); setNames(nextNames); setInputText(''); };
const nameList = names.map((name) => <li key={name.id}>{name.text}</li>); return ( <> <input value={inputText} onChange={onChange} /> <button onClick={onClick}>์ถ๊ฐ</button> <ul>{nameList}</ul> </> );};
export default IterationSample;
onChange
ํจ์๋ฅผ ํตํด inputText
๋ฅผ ์
๋ ฅ๋ฐ๋๋ก ํ๋ค.
๊ทธ๋ฆฌ๊ณ onClick
ํจ์์์๋ ๋ฐฐ์ด์ ๋ด์ฅ ํจ์ concat
์ ์ฌ์ฉํ์ฌ ์๋ก์ด ํญ๋ชฉ์์ถ๊ฐํ ๋ฐฐ์ด์ ๋ง๋ค์ด์ค ๋ค์, ์๋ก ๋ง๋ค์ด์ง nextNames
๋ฅผ setNames
๋ก ์ํ๋ฅผ์
๋ฐ์ดํธํด ์ค๋ค.
์ ํญ๋ชฉ์ ์ถ๊ฐํ ๋ ๋ฐฐ์ด์ push
ํจ์๊ฐ ์๋๋ผ concat
์ ์ฌ์ฉํ๋ ์ด์ ๊ฐ ์ค์ํ๋ฐ, push
ํจ์๋ ๊ธฐ์กด ๋ฐฐ์ด์ ํญ๋ชฉ์ ์ถ๊ฐํ๋ ๊ฒ์ผ๋ก ๊ธฐ์กด ๋ฐฐ์ด ์์ฒด๋ฅผ ๋ณ๊ฒฝํ๋๋ฐ๋ฉด, concat
ํจ์๋ ๊ธฐ์กด ๋ฐฐ์ด์ ํญ๋ชฉ์ ์ถ๊ฐํ ์๋ก์ด ๋ฐฐ์ด์ ๋ง๋ค์ด ์ค๋ค.
๋ฆฌ์กํธ์์ ์ํ๋ฅผ ์ ๋ฐ์ดํธํ ๋๋ ๊ธฐ์กด ์ํ๋ฅผ ๊ทธ๋๋ก ๋๋ฉด์ ์๋ก์ด ๊ฐ์ ์ํ๋ก์ค์ ํด์ผ ํ๋ค.
์ด๋ฅผ ๋ถ๋ณ์ฑ ์ ์ง๋ผ๊ณ ํ๋ฉฐ, ์ด๋ ๋ฆฌ์กํธ ์ปดํฌ๋ํธ์ ์ฑ๋ฅ์ ์ต์ ํํ๋๋ฐ ์ค์ํ ๊ฐ๋ ์ด๋ค.
๋ถ๋ณ์ฑ ์ ์ง์ ๋ํด์๋ ๋ค์์ ์์๋ณด๋๋ก ํ๋ค.
#
์ ๊ฑฐ ๊ธฐ๋ฅ ๊ตฌํํ๊ธฐ์ด๋ฒ์๋ ๊ฐ ํญ๋ชฉ์ ๋๋ธํด๋ฆญํ์ ๋ ํด๋น ํญ๋ชฉ์ด ์ฌ๋ผ์ง๋ ๊ธฐ๋ฅ์ ๊ตฌํํด ๋ณด๋๋ฐ, ๋ถ๋ณ์ฑ์ ์ ์งํ๋ฉด์ ๋ฐฐ์ด์ ํน์ ํญ๋ชฉ์ ์ง์ธ ๋๋ ๋ฐฐ์ด์ ๋ด์ฅ ํจ์ filter
๋ฅผ ์ฌ์ฉํ๋ค. filter
์ ์ฌ์ฉ ๋ฒ์ ์๋์ ๋งํฌ๋ฅผ ์ฐธ์กฐํ๋ค.
import React, {useState} from 'react';
const IterationSample = () => { const [names, setNames] = useState([ {id: 1, text: '๋์ฌ๋'}, {id: 2, text: '์ผ์'}, {id: 3, text: '๋'}, {id: 4, text: '๋ฐ๋'}, ]); const [inputText, setInputText] = useState(''); const [nextId, setNextId] = useState(5);
const onChange = (e) => setInputText(e.target.value); const onClick = () => { const nextNames = names.concat({ id: nextId, text: inputText, }); setNextId(nextId + 1); setNames(nextNames); setInputText(''); }; const onRemove = (id) => { const nextNames = names.filter((name) => name.id !== id); setNames(nextNames); }; const nameList = names.map((name) => ( <li key={name.id} onDoubleClick={() => onRemove(name.id)}> {name.text} </li> )); return ( <> <input value={inputText} onChange={onChange} /> <button onClick={onClick}>์ถ๊ฐ</button> <ul>{nameList}</ul> </> );};
export default IterationSample;
HTML ์์๋ฅผ ๋๋ธํด๋ฆญํ ๋ ์ฌ์ฉํ๋ ์ด๋ฒคํธ์ ์ด๋ฆ์ onDoubleClick
์ด๋ค. onRemove
๋ผ๋ ํจ์๋ฅผ ๊ตฌํํด์ ๊ฐ li
์์์ ์ด๋ฒคํธ๋ก ๋ฑ๋กํด์ค๋ค. onRemove
ํจ์์์๋ ํด๋ฆญํ ๋ ํด๋ฆญ์ด ๋ฐ์ํ li
์์์ id
๋ฅผ ๋งค๊ฐ๋ณ์๋ก ๋ฐ์ ํด๋น id
๋ฅผ ๊ฐ์ง name
๊ฐ์ฒด๋ฅผ ์ ๊ฑฐํ๊ณ , ํํฐ๋ง ๋ ๋ฐฐ์ด nextNames
๋ก names
๋ฅผ ์
๋ฐ์ดํธ ํ๋ค.
#
์ ๋ฆฌ๋ฐ๋ณต๋๋ ๋ฐ์ดํฐ๋ฅผ ๋ ๋๋งํ๊ณ , ์ ๋์ ์ธ ๋ฐฐ์ด์ ๋ง๋ค์ด ์ถ๊ฐ ๊ธฐ๋ฅ, ์ ๊ฑฐ ๊ธฐ๋ฅ์ ๊ตฌํํด ๋ณด์๋ค. ์ปดํฌ๋ํธ ๋ฐฐ์ด์ ๋ ๋๋งํ ๋๋ key
๊ฐ ์ค์ ์ ์ฃผ์ํด์ผ ํ๋ค.
๋ฐฐ์ด์ ๋ณํํ ๋๋ ๋ฐฐ์ด์ ์ง์ ์ ๊ทผํ์ฌ ์์ ํ๋ ๊ฒ์ด ์๋๋ผ concat
, filter
๋ฑ์ ๋ฐฐ์ด ๋ด์ฅ ํจ์๋ฅผ ์ฌ์ฉํ์ฌ ์๋ก์ด ๋ฐฐ์ด์ ๋ง๋ ํ ์ด๋ฅผ ์๋ก์ด ์ํ๋ก ์ค์ ํด์ฃผ์ด์ผ ํ๋ค๋ ์ ์ ๊ธฐ์ตํ์.