๋ณธ๋ฌธ์œผ๋กœ ๊ฑด๋„ˆ๋›ฐ๊ธฐ

[๋ฆฌ์•กํŠธ๋ฅผ ๋‹ค๋ฃจ๋Š” ๊ธฐ์ˆ ] 6์žฅ - ์ปดํฌ๋„ŒํŠธ ๋ฐ˜๋ณต

2020-04-03-๋ฆฌ์•กํŠธ๋ฅผ-๋‹ค๋ฃจ๋Š”-๊ธฐ์ˆ -6์žฅ-์ปดํฌ๋„ŒํŠธ-๋ฐ˜๋ณต-image-0

์ด ๊ธ€์€ ๊น€๋ฏผ์ค€(velopert)๋‹˜์˜ ๋ฆฌ์•กํŠธ๋ฅผ ๋‹ค๋ฃจ๋Š” ๊ธฐ์ˆ ์„์ฐธ์กฐํ•˜์—ฌ ์ž‘์„ฑํ•œ ๊ธ€์ž…๋‹ˆ๋‹ค.

์›น ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ๋งŒ๋“ค๋‹ค ๋ณด๋ฉด ๋ฐ˜๋ณต๋˜๋Š” ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•  ๋•Œ๊ฐ€ ์žˆ๋‹ค. ์ด ์žฅ์—์„œ๋Š” ๋ฆฌ์•กํŠธ ํ”„๋กœ์ ํŠธ์—์„œ ๋ฐ˜๋ณต์ ์ธ ์• ์šฉ์„ ํšจ์œจ์ ์œผ๋กœ ๋ณด์—ฌ์ฃผ๊ณ  ๊ด€๋ฆฌํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ์•Œ์•„๋ณธ๋‹ค.


์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ๋ฐฐ์—ด์˜ map() ํ•จ์ˆ˜#

์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ๋ฐฐ์—ด ๊ฐ์ฒด์˜ ๋‚ด์žฅ ํ•จ์ˆ˜์ธ map() ํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋ฐ˜๋ณต๋˜๋Š” ์ปดํฌ๋„ŒํŠธ๋ฅผ๋ Œ๋”๋งํ•  ์ˆ˜ ์žˆ๋‹ค.

๋จผ์ € map() ํ•จ์ˆ˜์— ๋Œ€ํ•œ mdn ๋ฌธ์„œ๋ฅผ ๋ณด๊ณ  ์ •๋ฆฌํ•ด๋ณธ๋‹ค

Array.prototype.map()

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() ํ•จ์ˆ˜๋ฅผ ์ดํ•ดํ•ด์•ผํ•œ๋‹ค.

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;

2020-04-03-๋ฆฌ์•กํŠธ๋ฅผ-๋‹ค๋ฃจ๋Š”-๊ธฐ์ˆ -6์žฅ-์ปดํฌ๋„ŒํŠธ-๋ฐ˜๋ณต-image-1

์›ํ•˜๋Š” ๋Œ€๋กœ ๋ Œ๋”๋ง์ด ๋œ ๊ฒƒ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค.

ํ•˜์ง€๋งŒ F12 ํ‚ค๋ฅผ ๋ˆŒ๋Ÿฌ ํฌ๋กฌ์˜ ์ฝ˜์†” ์ฐฝ์„ ํ™•์ธํ•ด ๋ณด๋ฉด ๊ฒฝ๊ณ  ๋ฉ”์‹œ์ง€๊ฐ€ ๋‚˜ํƒ€๋‚˜๋Š” ๊ฒƒ์„๋ณผ ์ˆ˜ ์žˆ๋‹ค.

2020-04-03-๋ฆฌ์•กํŠธ๋ฅผ-๋‹ค๋ฃจ๋Š”-๊ธฐ์ˆ -6์žฅ-์ปดํฌ๋„ŒํŠธ-๋ฐ˜๋ณต-image-2

๊ฒฝ๊ณ  ๋ฉ”์‹œ์ง€๋ฅผ ๋ณด๋ฉด ๋ฆฌ์ŠคํŠธ์— ์žˆ๋Š” ๊ฐ ์ž์† ์š”์†Œ(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 ์˜ ์‚ฌ์šฉ ๋ฒ•์€ ์•„๋ž˜์˜ ๋งํฌ๋ฅผ ์ฐธ์กฐํ•œ๋‹ค.

Array.prototype.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 ๋“ฑ์˜ ๋ฐฐ์—ด ๋‚ด์žฅ ํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์ƒˆ๋กœ์šด ๋ฐฐ์—ด์„ ๋งŒ๋“  ํ›„ ์ด๋ฅผ ์ƒˆ๋กœ์šด ์ƒํƒœ๋กœ ์„ค์ •ํ•ด์ฃผ์–ด์•ผ ํ•œ๋‹ค๋Š” ์ ์„ ๊ธฐ์–ตํ•˜์ž.

๊ฐ™์ด ์ฝ๊ธฐ#

๋ฆฌ์ŠคํŠธ์™€ Key - React