๋ฐฐ์ด State ์ ๋ฐ์ดํธํ๊ธฐ
๋ฐฐ์ด์ JavaScript์์๋ ๋ณ๊ฒฝ์ด ๊ฐ๋ฅํ์ง๋ง, state๋ก ์ ์ฅํ ๋์๋ ๋ณ๊ฒฝํ ์ ์๋๋ก ์ฒ๋ฆฌํด์ผ ํฉ๋๋ค. ๊ฐ์ฒด์ ๋ง์ฐฌ๊ฐ์ง๋ก, state์ ์ ์ฅ๋ ๋ฐฐ์ด์ ์ ๋ฐ์ดํธํ๊ณ ์ถ์ ๋์๋, ์ ๋ฐฐ์ด์ ์์ฑ(ํน์ ๊ธฐ์กด ๋ฐฐ์ด์ ๋ณต์ฌ๋ณธ์ ์์ฑ)ํ ๋ค, ์ด ์ ๋ฐฐ์ด์ state๋ก ๋์ด ์ ๋ฐ์ดํธํด์ผ ํฉ๋๋ค.
ํ์ต ๋ด์ฉ
- React state์์ ๋ฐฐ์ด์ ํญ๋ชฉ์ ์ถ๊ฐ, ์ญ์ ๋๋ ๋ณ๊ฒฝํ๋ ๋ฐฉ๋ฒ
- ๋ฐฐ์ด ๋ด๋ถ์ ๊ฐ์ฒด๋ฅผ ์ ๋ฐ์ดํธํ๋ ๋ฐฉ๋ฒ
- Immer๋ก ๋ ๋ฐ๋ณตํด์ ๋ฐฐ์ด์ ๋ณต์ฌํ๋ ๋ฐฉ๋ฒ
๋ณ๊ฒฝํ์ง ์๊ณ ๋ฐฐ์ด ์ ๋ฐ์ดํธํ๊ธฐ
JavaScript์์ ๋ฐฐ์ด์ ๋ค๋ฅธ ์ข
๋ฅ์ ๊ฐ์ฒด์
๋๋ค. ๊ฐ์ฒด์ ๋ง์ฐฌ๊ฐ์ง๋ก React state์์ ๋ฐฐ์ด์ ์ฝ๊ธฐ ์ ์ฉ์ผ๋ก ์ฒ๋ฆฌํด์ผ ํฉ๋๋ค. ์ฆ arr[0] = 'bird'
์ฒ๋ผ ๋ฐฐ์ด ๋ด๋ถ์ ํญ๋ชฉ์ ์ฌํ ๋นํด์๋ ์ ๋๋ฉฐ push()
๋ pop()
๊ฐ์ ํจ์๋ก ๋ฐฐ์ด์ ๋ณ๊ฒฝํด์๋ ์๋ฉ๋๋ค.
๋์ ๋ฐฐ์ด์ ์
๋ฐ์ดํธํ ๋๋ง๋ค ์ ๋ฐฐ์ด์ state ์ค์ ํจ์์ ์ ๋ฌํด์ผ ํฉ๋๋ค. ์ด๋ฅผ ์ํด state์ ์๋ณธ ๋ฐฐ์ด์ ๋ณ๊ฒฝ์ํค์ง ์๋ filter()
์ map()
๊ฐ์ ํจ์๋ฅผ ์ฌ์ฉํ์ฌ ์๋ณธ ๋ฐฐ์ด๋ก๋ถํฐ ์ ๋ฐฐ์ด์ ๋ง๋ค ์ ์์ต๋๋ค. ์ดํ ์ด ์ ๋ฐฐ์ด๋ค์ state์ ์ค์ ํฉ๋๋ค.
๋ค์์ ์ผ๋ฐ์ ์ธ ๋ฐฐ์ด ์ฐ์ฐ์ ๋ํ ์ฐธ์กฐ ํ์ ๋๋ค. React state ๋ด์์ ๋ฐฐ์ด์ ๋ค๋ฃฐ ๋, ์ผ์ชฝ ์ด์ ์๋ ํจ์๋ค์ ์ฌ์ฉ์ ํผํ๋ ๋์ , ์ค๋ฅธ์ชฝ ์ด์ ์๋ ํจ์๋ค์ ์ ํธํด์ผ ํฉ๋๋ค.
๋น์ ํธ (๋ฐฐ์ด์ ๋ณ๊ฒฝ) | ์ ํธ (์ ๋ฐฐ์ด์ ๋ฐํ) | |
---|---|---|
์ถ๊ฐ | push , unshift | concat , [...arr] ์ ๊ฐ ์ฐ์ฐ์ (์์) |
์ ๊ฑฐ | pop , shift , splice | filter , slice (์์) |
๊ต์ฒด | splice , arr[i] = ... ํ ๋น | map (์์) |
์ ๋ ฌ | reverse , sort | ๋ฐฐ์ด์ ๋ณต์ฌํ ์ดํ ์ฒ๋ฆฌ (์์) |
๋๋ ๋ ์ด์ ํจ์๋ฅผ ๋ชจ๋ ์ฌ์ฉํ ์ ์๋๋ก ํ๋ Immer๋ฅผ ์ฌ์ฉํ ์ ์์ต๋๋ค.
๋ฐฐ์ด์ ํญ๋ชฉ ์ถ๊ฐํ๊ธฐ
push()
๋ ๋ฐฐ์ด์ ๋ณ๊ฒฝํฉ๋๋ค. (์์น ์๋ ๋ฐฉ์)
import { useState } from 'react'; let nextId = 0; export default function List() { const [name, setName] = useState(''); const [artists, setArtists] = useState([]); return ( <> <h1>Inspiring sculptors:</h1> <input value={name} onChange={e => setName(e.target.value)} /> <button onClick={() => { artists.push({ id: nextId++, name: name, }); }}>Add</button> <ul> {artists.map(artist => ( <li key={artist.id}>{artist.name}</li> ))} </ul> </> ); }
๋์ ๊ธฐ์กด์ ์กด์ฌํ๋ ํญ๋ชฉ๋ค ๋ค์ ์ ํญ๋ชฉ์ ํฌํจํ๋ ์๋ก์ด ๋ฐฐ์ด์ ๋ง๋์ธ์. ์ด๋ฅผ ์ํ ๋ฐฉ๋ฒ์ ์ฌ๋ฌ ๊ฐ์ง๊ฐ ์์ง๋ง ๊ฐ์ฅ ์ฌ์ด ๋ฐฉ๋ฒ์ ...
๋ฐฐ์ด ์ ๊ฐ ๊ตฌ๋ฌธ์ ์ฌ์ฉํ๋ ๊ฒ์
๋๋ค.
setArtists( // ์๋์ ์๋ก์ด ๋ฐฐ์ด๋ก state๋ฅผ ๋ณ๊ฒฝํฉ๋๋ค.
[
...artists, // ๊ธฐ์กด ๋ฐฐ์ด์ ๋ชจ๋ ํญ๋ชฉ์,
{ id: nextId++, name: name } // ๋ง์ง๋ง์ ์ ํญ๋ชฉ์ ์ถ๊ฐํฉ๋๋ค.
]
);
์ด์ ์ฌ๋ฐ๋ฅด๊ฒ ์๋ํฉ๋๋ค.
import { useState } from 'react'; let nextId = 0; export default function List() { const [name, setName] = useState(''); const [artists, setArtists] = useState([]); return ( <> <h1>Inspiring sculptors:</h1> <input value={name} onChange={e => setName(e.target.value)} /> <button onClick={() => { setArtists([ ...artists, { id: nextId++, name: name } ]); }}>Add</button> <ul> {artists.map(artist => ( <li key={artist.id}>{artist.name}</li> ))} </ul> </> ); }
๋ฐฐ์ด ์ ๊ฐ ๊ตฌ๋ฌธ์ ์ฌ์ฉํ์ฌ ๊ธฐ์กด ๋ฐฐ์ด์ธ ...artists
์ ์์ ํญ๋ชฉ์ ๋ฐฐ์นํ์ฌ ์ถ๊ฐํ ์๋ ์์ต๋๋ค.
setArtists([
{ id: nextId++, name: name }, // ์ถ๊ฐํ ํญ๋ชฉ์ ์์ ๋ฐฐ์นํ๊ณ ,
...artists // ๊ธฐ์กด ๋ฐฐ์ด์ ํญ๋ชฉ๋ค์ ๋ค์ ๋ฐฐ์นํฉ๋๋ค.
]);
์ด๋ฐ ์์ผ๋ก ์ ๊ฐ ๊ตฌ๋ฌธ์ ๋ฐฐ์ด์ ๊ฐ์ฅ ๋ค์ ์ถ๊ฐํ๋ push()
์, ๋ฐฐ์ด์ ๊ฐ์ฅ ์์ ์ถ๊ฐํ๋ unshift()
์ ๋ ๊ธฐ๋ฅ ๋ชจ๋ ์ํํ ์ ์์ต๋๋ค. ์์ ์๋๋ฐ์ค์์ ์ฌ์ฉํด๋ณด์ธ์!
๋ฐฐ์ด์์ ํญ๋ชฉ ์ ๊ฑฐํ๊ธฐ
๋ฐฐ์ด์์ ํญ๋ชฉ์ ์ ๊ฑฐํ๋ ๊ฐ์ฅ ์ฌ์ด ๋ฐฉ๋ฒ์ ํํฐ๋งํ๋ ๊ฒ์
๋๋ค. ๋ค์ ๋งํด์ ํด๋น ํญ๋ชฉ์ ํฌํจํ์ง ์๋ ์ ๋ฐฐ์ด์ ์ ๊ณตํ๋ ๊ฒ์
๋๋ค. ์ด๋ ๊ฒ ํ๋ ค๋ฉด filter
ํจ์๋ฅผ ์ฌ์ฉํ๋ฉด ๋ฉ๋๋ค. ์๋ฅผ ๋ค๋ฉด ์๋์ ๊ฐ์ต๋๋ค.
import { useState } from 'react'; let initialArtists = [ { id: 0, name: 'Marta Colvin Andrade' }, { id: 1, name: 'Lamidi Olonade Fakeye'}, { id: 2, name: 'Louise Nevelson'}, ]; export default function List() { const [artists, setArtists] = useState( initialArtists ); return ( <> <h1>Inspiring sculptors:</h1> <ul> {artists.map(artist => ( <li key={artist.id}> {artist.name}{' '} <button onClick={() => { setArtists( artists.filter(a => a.id !== artist.id ) ); }}> Delete </button> </li> ))} </ul> </> ); }
โDeleteโ ๋ฒํผ์ ๋ช ๋ฒ ํด๋ฆญํ๊ณ , ํด๋ฆญ ์ด๋ฒคํธ ํธ๋ค๋ฌ๋ฅผ ํ์ธํด๋ณด์ธ์.
setArtists(
artists.filter(a => a.id !== artist.id)
);
์ฌ๊ธฐ์ artists.filter(s => s.id !== artist.id)
๋ โartist.id
์ ID๊ฐ ๋ค๋ฅธ artists
๋ก ๊ตฌ์ฑ๋ ๋ฐฐ์ด์ ์์ฑํ๋คโ๋ ์๋ฏธ์
๋๋ค. ์ฆ, ๊ฐ artist์ โDeleteโ ๋ฒํผ์ ํด๋น artist๋ฅผ ๋ฐฐ์ด์์ ํํฐ๋งํ ๋ค์, ๋ฐํ๋ ๋ฐฐ์ด๋ก ๋ฆฌ๋ ๋๋ง์ ์์ฒญํฉ๋๋ค. filter
๊ฐ ์๋ณธ ๋ฐฐ์ด์ ์์ ํ์ง ์๋๋ค๋ ์ ์ ์ฃผ์ํ์ธ์.
๋ฐฐ์ด ๋ณํํ๊ธฐ
๋ฐฐ์ด์ ์ผ๋ถ ๋๋ ์ ์ฒด ํญ๋ชฉ์ ๋ณ๊ฒฝํ๊ณ ์ ํ๋ค๋ฉด, map()
์ ์ฌ์ฉํด ์๋ก์ด ๋ฐฐ์ด์ ๋ง๋ค ์ ์์ต๋๋ค. map
์ ์ ๋ฌํ ํจ์๋ ๋ฐ์ดํฐ๋ ์ธ๋ฑ์ค(๋๋ ๋ ๋ค)๋ฅผ ๊ธฐ๋ฐ์ผ๋ก ๊ฐ ํญ๋ชฉ์ ์ด๋ป๊ฒ ์ฒ๋ฆฌํ ์ง ๊ฒฐ์ ํ ์ ์์ต๋๋ค.
์ด ์์์์ ๋ฐฐ์ด์ ๋ ๊ฐ์ ์๊ณผ ํ๋์ ์ ์ฌ๊ฐํ ์ขํ๋ฅผ ๊ฐ์ง๋๋ค. ๋ฒํผ์ ๋๋ฅด๋ฉด, ์๋ค์ 50ํฝ์
์๋๋ก ์ด๋ํฉ๋๋ค. map()
์ผ๋ก ์ ๋ฐ์ดํฐ ๋ฐฐ์ด์ ์์ฑํ์ฌ ์ด๋ฅผ ์ฒ๋ฆฌํฉ๋๋ค.
import { useState } from 'react'; let initialShapes = [ { id: 0, type: 'circle', x: 50, y: 100 }, { id: 1, type: 'square', x: 150, y: 100 }, { id: 2, type: 'circle', x: 250, y: 100 }, ]; export default function ShapeEditor() { const [shapes, setShapes] = useState( initialShapes ); function handleClick() { const nextShapes = shapes.map(shape => { if (shape.type === 'square') { // ๋ณ๊ฒฝ์ํค์ง ์๊ณ ๋ฐํํฉ๋๋ค. return shape; } else { // 50px ์๋๋ก ์ด๋ํ ์๋ก์ด ์์ ๋ฐํํฉ๋๋ค. return { ...shape, y: shape.y + 50, }; } }); // ์๋ก์ด ๋ฐฐ์ด๋ก ๋ฆฌ๋ ๋๋งํฉ๋๋ค. setShapes(nextShapes); } return ( <> <button onClick={handleClick}> Move circles down! </button> {shapes.map(shape => ( <div style={{ background: 'purple', position: 'absolute', left: shape.x, top: shape.y, borderRadius: shape.type === 'circle' ? '50%' : '', width: 20, height: 20, }} /> ))} </> ); }
๋ฐฐ์ด ๋ด ํญ๋ชฉ ๊ต์ฒดํ๊ธฐ
๋ฐฐ์ด์์ ํ๋ ์ด์์ ํญ๋ชฉ์ ๊ต์ฒดํ๋ ๊ฒฝ์ฐ๊ฐ ํนํ ํํฉ๋๋ค. arr[0] = 'bird'
์ ๊ฐ์ ํ ๋น์ ์๋ณธ ๋ฐฐ์ด์ ๋ณ๊ฒฝ์ํค๋ฏ๋ก, ์ด ๊ฒฝ์ฐ์๋ map
์ ์ฌ์ฉํ๋ ํธ์ด ์ข์ต๋๋ค.
ํญ๋ชฉ์ ๊ต์ฒดํ๊ธฐ ์ํด map
์ ์ด์ฉํด์ ์๋ก์ด ๋ฐฐ์ด์ ๋ง๋ญ๋๋ค. map
์ ํธ์ถํ ๋ ๋ ๋ฒ์งธ ์ธ์๋ก ํญ๋ชฉ์ ์ธ๋ฑ์ค๋ฅผ ๋ฐ์ ์ ์์ต๋๋ค. ์ธ๋ฑ์ค๋ ์๋ ํญ๋ชฉ(์ฒซ ๋ฒ์งธ ์ธ์)์ ๋ฐํํ ์ง ๋ค๋ฅธ ํญ๋ชฉ์ ๋ฐํํ ์ง๋ฅผ ๊ฒฐ์ ํ ๋ ์ฌ์ฉํฉ๋๋ค.
import { useState } from 'react'; let initialCounters = [ 0, 0, 0 ]; export default function CounterList() { const [counters, setCounters] = useState( initialCounters ); function handleIncrementClick(index) { const nextCounters = counters.map((c, i) => { if (i === index) { // ํด๋ฆญ๋ counter๋ฅผ ์ฆ๊ฐ์ํต๋๋ค. return c + 1; } else { // ๋ณ๊ฒฝ๋์ง ์์ ๋๋จธ์ง๋ฅผ ๋ฐํํฉ๋๋ค. return c; } }); setCounters(nextCounters); } return ( <ul> {counters.map((counter, i) => ( <li key={i}> {counter} <button onClick={() => { handleIncrementClick(i); }}>+1</button> </li> ))} </ul> ); }
๋ฐฐ์ด์ ํญ๋ชฉ ์ฝ์ ํ๊ธฐ
๊ฐ๋์ ์์๋, ๋๋ ์๋ ์์น์ ํญ๋ชฉ์ ์ฝ์
ํ๊ณ ์ถ์ ์ ์์ต๋๋ค. ์ด๋ฅผ ์ํด, ...
๋ฐฐ์ด ์ ๊ฐ ๊ตฌ๋ฌธ๊ณผ slice()
ํจ์๋ฅผ ํจ๊ป ์ฌ์ฉํ ์ ์์ต๋๋ค. slice()
ํจ์๋ฅผ ์ฌ์ฉํ๋ฉด ๋ฐฐ์ด์ โ์ผ๋ถ๋ถโ์ ์๋ผ๋ผ ์ ์์ต๋๋ค. ํญ๋ชฉ์ ์ฝ์
ํ๋ ค๋ฉด ์ฝ์
์ง์ ์์ ์๋ฅธ ๋ฐฐ์ด์ ์ ๊ฐํ๊ณ , ์ ํญ๋ชฉ๊ณผ ์๋ณธ ๋ฐฐ์ด์ ๋๋จธ์ง ๋ถ๋ถ์ ์ ๊ฐํ๋ ๋ฐฐ์ด์ ๋ง๋ญ๋๋ค.
์ด ์์์์ ์ฝ์
๋ฒํผ์ ํญ์ ์ธ๋ฑ์ค 1
์ ์ฝ์
๋ฉ๋๋ค.
import { useState } from 'react'; let nextId = 3; const initialArtists = [ { id: 0, name: 'Marta Colvin Andrade' }, { id: 1, name: 'Lamidi Olonade Fakeye'}, { id: 2, name: 'Louise Nevelson'}, ]; export default function List() { const [name, setName] = useState(''); const [artists, setArtists] = useState( initialArtists ); function handleClick() { const insertAt = 1; // ๋ชจ๋ ์ธ๋ฑ์ค๊ฐ ๋ ์ ์์ต๋๋ค. const nextArtists = [ // ์ฝ์ ์ง์ ์ด์ ํญ๋ชฉ ...artists.slice(0, insertAt), // ์ ํญ๋ชฉ { id: nextId++, name: name }, // ์ฝ์ ์ง์ ์ดํ ํญ๋ชฉ ...artists.slice(insertAt) ]; setArtists(nextArtists); setName(''); } return ( <> <h1>Inspiring sculptors:</h1> <input value={name} onChange={e => setName(e.target.value)} /> <button onClick={handleClick}> Insert </button> <ul> {artists.map(artist => ( <li key={artist.id}>{artist.name}</li> ))} </ul> </> ); }
๋ฐฐ์ด์ ๊ธฐํ ๋ณ๊ฒฝ ์ ์ฉํ๊ธฐ
์ ๊ฐ ๊ตฌ๋ฌธ๊ณผ map()
, filter()
๊ฐ์ ๋น-๋ณ๊ฒฝ ํจ์๋ค๋ก๋ง์ผ๋ก๋ ํ ์ ์๋ ์ผ์ด ๋ช ๊ฐ์ง ์์ต๋๋ค. ์๋ฅผ ๋ค์ด ๋ฐฐ์ด์ ๋ค์ง๊ฑฐ๋ ์ ๋ ฌํ๊ณ ์ถ์ ์ ์์ต๋๋ค. JavaScript์ reverse()
๋ฐ sort()
ํจ์๋ ์๋ณธ ๋ฐฐ์ด์ ๋ณ๊ฒฝ์ํค๋ฏ๋ก ์ง์ ์ฌ์ฉํ ์ ์์ต๋๋ค.
๋์ , ๋จผ์ ๋ฐฐ์ด์ ๋ณต์ฌํ ๋ค ๋ณ๊ฒฝํ ์ ์์ต๋๋ค.
์๋ฅผ ๋ค์ด์ ์๋์ ๊ฐ์ต๋๋ค.
import { useState } from 'react'; const initialList = [ { id: 0, title: 'Big Bellies' }, { id: 1, title: 'Lunar Landscape' }, { id: 2, title: 'Terracotta Army' }, ]; export default function List() { const [list, setList] = useState(initialList); function handleClick() { const nextList = [...list]; nextList.reverse(); setList(nextList); } return ( <> <button onClick={handleClick}> Reverse </button> <ul> {list.map(artwork => ( <li key={artwork.id}>{artwork.title}</li> ))} </ul> </> ); }
์ฌ๊ธฐ์๋ ๋จผ์ [...list]
์ ๊ฐ ๊ตฌ๋ฌธ์ ์ฌ์ฉํด ์๋ณธ ๋ฐฐ์ด์ ๋ณต์ฌ๋ณธ์ ๋ง๋ญ๋๋ค. ์ด์ ๋ณต์ฌ๋ณธ์ด ์์ผ๋ฏ๋ก nextList.reverse()
๋๋ nextList.sort()
์ ๊ฐ์ ๋ณ๊ฒฝ ํจ์๋ฅผ ์ฌ์ฉํ๊ฑฐ๋ nextList[0] = "something"
๊ณผ ๊ฐ์ด ๊ฐ๋ณ ํญ๋ชฉ์ ํ ๋นํ ์๋ ์์ต๋๋ค.
๊ทธ๋ฌ๋, ๋ฐฐ์ด์ ๋ณต์ฌํ๋๋ผ๋ ๋ฐฐ์ด ๋ด๋ถ ์ ๊ธฐ์กด ํญ๋ชฉ์ ์ง์ ๋ณ๊ฒฝํด์๋ ์๋ฉ๋๋ค. ์ด๋ ์์ ๋ณต์ฌ์ด๊ธฐ ๋๋ฌธ์ ๋ณต์ฌํ ์ ๋ฐฐ์ด์๋ ์๋ณธ ๋ฐฐ์ด๊ณผ ๋์ผํ ํญ๋ชฉ์ด ํฌํจ๋ฉ๋๋ค. ๋ฐ๋ผ์ ๋ณต์ฌ๋ ๋ฐฐ์ด ๋ด๋ถ์ ๊ฐ์ฒด๋ฅผ ์์ ํ๋ฉด ๊ธฐ์กด state๊ฐ ๋ณ๊ฒฝ๋ฉ๋๋ค. ์๋ฅผ ๋ค๋ฉด, ์๋์ ๊ฐ์ ์ฝ๋๊ฐ ๋ฌธ์ ๊ฐ ๋ฉ๋๋ค.
const nextList = [...list];
nextList[0].seen = true; // ๋ฌธ์ : list[0]์ ๋ณ๊ฒฝ์ํต๋๋ค.
setList(nextList);
nextList
์ list
๋ ์๋ก ๋ค๋ฅธ ๋ฐฐ์ด์ด์ง๋ง, nextList[0]
๊ณผ list[0]
์ ๋์ผํ ๊ฐ์ฒด๋ฅผ ๊ฐ๋ฆฌํต๋๋ค. ๋ฐ๋ผ์ nextList[0].seen
์ ๋ณ๊ฒฝํ๋ฉด list[0].seen
๋ ๋ณ๊ฒฝ๋ฉ๋๋ค. ์ด๊ฒ์ state ๋ณ๊ฒฝ์ด๋ฏ๋ก ํผํด์ผ ํฉ๋๋ค. ์ค์ฒฉ๋ JavaScript ๊ฐ์ฒด ์
๋ฐ์ดํธ์ ์ ์ฌํ ๋ฐฉ์์ผ๋ก ์ด ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ ์ ์์ต๋๋ค. ๋ณ๊ฒฝํ๋ ค๋ ๊ฐ๋ณ ํญ๋ชฉ์ ๋ณ๊ฒฝํ๋ ๋์ ๋ณต์ฌํฉ๋๋ค. ๋ฐฉ๋ฒ์ ๋ค์๊ณผ ๊ฐ์ต๋๋ค.
๋ฐฐ์ด ๋ด๋ถ์ ๊ฐ์ฒด ์ ๋ฐ์ดํธํ๊ธฐ
๊ฐ์ฒด๋ ์ค์ ๋ก ๋ฐฐ์ด โ๋ด๋ถโ์ ์์นํ์ง ์์ต๋๋ค. ์ฝ๋์์ โ๋ด๋ถโ๋ก ๋ํ๋ผ ์ ์์ง๋ง ๋ฐฐ์ด์ ๊ฐ ๊ฐ์ฒด๋ ๋ฐฐ์ด์ด โ๊ฐ๋ฆฌํค๋โ ๋ณ๋์ ๊ฐ์
๋๋ค. ์ด๊ฒ์ด list[0]
์ฒ๋ผ ์ค์ฒฉ๋ ํ๋๋ฅผ ๋ณ๊ฒฝํ ๋ ์ฃผ์ํด์ผ ํ๋ ์ด์ ์
๋๋ค. ๋ค๋ฅธ ์ฌ๋์ artwork ๋ชฉ๋ก์ด ๋ฐฐ์ด์ ๋์ผํ ์์๋ฅผ ๊ฐ๋ฆฌํฌ ์ ์์ต๋๋ค!
์ค์ฒฉ๋ state๋ฅผ ์ ๋ฐ์ดํธํ ๋, ์ ๋ฐ์ดํธํ๋ ค๋ ์ง์ ๋ถํฐ ์ต์์ ๋ ๋ฒจ๊น์ง์ ๋ณต์ฌ๋ณธ์ ๋ง๋ค์ด์ผ ํฉ๋๋ค. ์ด๋ป๊ฒ ์๋ํ๋์ง ์ดํด๋ด ์๋ค.
์๋ ์์์์ ๋ ๊ฐ์ ๊ฐ๋ณ artwork ๋ชฉ๋ก๋ค์ ์ด๊ธฐ state๊ฐ ์๋ก ๊ฐ์ต๋๋ค. ๋ ๋ฆฌ์คํธ๋ ๋ถ๋ฆฌ๋์ด์ผ ํ์ง๋ง ๋ณ๊ฒฝ์ผ๋ก ์ธํด ๋ ๋ชฉ๋ก์ state๊ฐ ์ค์๋ก ๊ณต์ ๋๊ณ ํ ๋ชฉ๋ก์ ์ฒดํฌ๋ฐ์ค๋ฅผ ์ ํํ๋ฉด ๋ค๋ฅธ ๋ชฉ๋ก์๋ ์ํฅ์ ๋ฏธ์นฉ๋๋ค.
import { useState } from 'react'; let nextId = 3; const initialList = [ { id: 0, title: 'Big Bellies', seen: false }, { id: 1, title: 'Lunar Landscape', seen: false }, { id: 2, title: 'Terracotta Army', seen: true }, ]; export default function BucketList() { const [myList, setMyList] = useState(initialList); const [yourList, setYourList] = useState( initialList ); function handleToggleMyList(artworkId, nextSeen) { const myNextList = [...myList]; const artwork = myNextList.find( a => a.id === artworkId ); artwork.seen = nextSeen; setMyList(myNextList); } function handleToggleYourList(artworkId, nextSeen) { const yourNextList = [...yourList]; const artwork = yourNextList.find( a => a.id === artworkId ); artwork.seen = nextSeen; setYourList(yourNextList); } return ( <> <h1>Art Bucket List</h1> <h2>My list of art to see:</h2> <ItemList artworks={myList} onToggle={handleToggleMyList} /> <h2>Your list of art to see:</h2> <ItemList artworks={yourList} onToggle={handleToggleYourList} /> </> ); } function ItemList({ artworks, onToggle }) { return ( <ul> {artworks.map(artwork => ( <li key={artwork.id}> <label> <input type="checkbox" checked={artwork.seen} onChange={e => { onToggle( artwork.id, e.target.checked ); }} /> {artwork.title} </label> </li> ))} </ul> ); }
๋ฌธ์ ๋ ์๋์ ๊ฐ์ ์ฝ๋์ ์์ต๋๋ค.
const myNextList = [...myList];
const artwork = myNextList.find(a => a.id === artworkId);
artwork.seen = nextSeen; // ๋ฌธ์ : ๊ธฐ์กด ํญ๋ชฉ์ ๋ณ๊ฒฝ์ํต๋๋ค.
setMyList(myNextList);
myNextList
๋ฐฐ์ด ์์ฒด๋ ์๋ก์ด ๋ฐฐ์ด์ด์ง๋ง, ํญ๋ชฉ ์์ฒด๋ myList
์๋ณธ ๋ฐฐ์ด๊ณผ ๋์ผํฉ๋๋ค. ๋ฐ๋ผ์ artwork.seen
์ ๋ณ๊ฒฝํ๋ฉด ์๋ณธ artwork ํญ๋ชฉ์ด ๋ณ๊ฒฝ๋ฉ๋๋ค. ํด๋น artwork ํญ๋ชฉ์ yourArtWorks
์๋ ์กด์ฌํ๋ฏ๋ก ๋ฒ๊ทธ๊ฐ ๋ฐ์ํฉ๋๋ค. ์ด๋ฐ ๋ฒ๊ทธ๋ ์๊ฐํ๊ธฐ ์ด๋ ค์ธ ์ ์์ง๋ง ๋คํํ๋ state ๋ณ๊ฒฝ์ ํผํ๋ฉด ํด๊ฒฐํ ์ ์์ต๋๋ค.
map
์ ์ฌ์ฉํ๋ฉด ์ด์ ํญ๋ชฉ์ ๋ณ๊ฒฝ ์์ด ์
๋ฐ์ดํธ๋ ๋ฒ์ ์ผ๋ก ๋์ฒดํ ์ ์์ต๋๋ค.
setMyList(myList.map(artwork => {
if (artwork.id === artworkId) {
// ๋ณ๊ฒฝ๋ *์* ๊ฐ์ฒด๋ฅผ ๋ง๋ค์ด ๋ฐํํฉ๋๋ค.
return { ...artwork, seen: nextSeen };
} else {
// ๋ณ๊ฒฝ์ํค์ง ์๊ณ ๋ฐํํฉ๋๋ค.
return artwork;
}
}));
์ฌ๊ธฐ์ ...
๋ ๊ฐ์ฒด์ ๋ณต์ฌ๋ณธ ์์ฑ์ ์ฌ์ฉ๋๋ ๊ฐ์ฒด ์ ๊ฐ ๊ตฌ๋ฌธ์
๋๋ค.
์ด ์ ๊ทผ ๋ฐฉ์์ ์ฌ์ฉํ๋ฉด, ๊ธฐ์กด state ํญ๋ชฉ์ด ๋ณ๊ฒฝ๋์ง ์๊ณ , ๋ฒ๊ทธ๊ฐ ์์ ๋ฉ๋๋ค.
import { useState } from 'react'; let nextId = 3; const initialList = [ { id: 0, title: 'Big Bellies', seen: false }, { id: 1, title: 'Lunar Landscape', seen: false }, { id: 2, title: 'Terracotta Army', seen: true }, ]; export default function BucketList() { const [myList, setMyList] = useState(initialList); const [yourList, setYourList] = useState( initialList ); function handleToggleMyList(artworkId, nextSeen) { setMyList(myList.map(artwork => { if (artwork.id === artworkId) { // ๋ณ๊ฒฝ๋ *์* ๊ฐ์ฒด๋ฅผ ๋ง๋ค์ด ๋ฐํํฉ๋๋ค. return { ...artwork, seen: nextSeen }; } else { // ๋ณ๊ฒฝ์ํค์ง ์๊ณ ๋ฐํํฉ๋๋ค. return artwork; } })); } function handleToggleYourList(artworkId, nextSeen) { setYourList(yourList.map(artwork => { if (artwork.id === artworkId) { // ๋ณ๊ฒฝ๋ *์* ๊ฐ์ฒด๋ฅผ ๋ง๋ค์ด ๋ฐํํฉ๋๋ค. return { ...artwork, seen: nextSeen }; } else { // ๋ณ๊ฒฝ์ํค์ง ์๊ณ ๋ฐํํฉ๋๋ค. return artwork; } })); } return ( <> <h1>Art Bucket List</h1> <h2>My list of art to see:</h2> <ItemList artworks={myList} onToggle={handleToggleMyList} /> <h2>Your list of art to see:</h2> <ItemList artworks={yourList} onToggle={handleToggleYourList} /> </> ); } function ItemList({ artworks, onToggle }) { return ( <ul> {artworks.map(artwork => ( <li key={artwork.id}> <label> <input type="checkbox" checked={artwork.seen} onChange={e => { onToggle( artwork.id, e.target.checked ); }} /> {artwork.title} </label> </li> ))} </ul> ); }
์ผ๋ฐ์ ์ผ๋ก ๋ฐฉ๊ธ ์์ฑํ ๊ฐ์ฒด๋ง ๋ณ๊ฒฝํด์ผ ํฉ๋๋ค. ์ artwork๋ฅผ ์ฝ์ ํ๋ ๊ฒฝ์ฐ ๋ณ๊ฒฝ์ด ๊ฐ๋ฅํ์ง๋ง, ์ด๋ฏธ state์ ์กด์ฌํ๋ ๊ฒ์ ์ฒ๋ฆฌํ๋ ค๋ฉด ๋ณต์ฌ๋ณธ์ ๋ง๋ค์ด์ผ ํฉ๋๋ค.
Immer๋ก ๊ฐ๊ฒฐํ ์ ๋ฐ์ดํธ ๋ก์ง ์์ฑํ๊ธฐ
๋ณ๊ฒฝ ์์ด ์ค์ฒฉ๋ ๋ฐฐ์ด์ ์ ๋ฐ์ดํธํ๋ ๊ฒ์ ๊ฐ์ฒด์ ๋ง์ฐฌ๊ฐ์ง๋ก ์ฝ๊ฐ ๋ฐ๋ณต์ ์ผ ์ ์์ต๋๋ค.
- ์ผ๋ฐ์ ์ผ๋ก ๊น์ ๋ ๋ฒจ๊น์ง์ state๋ฅผ ์ ๋ฐ์ดํธํ ํ์๋ ์์ต๋๋ค. state ๊ฐ์ฒด๊ฐ ๋งค์ฐ ๊น๋ค๋ฉด ๋ค๋ฅด๊ฒ ์ฌ๊ตฌ์ฑํ์ฌ ํํํ๊ฒ ๋ง๋ค ์ ์์ต๋๋ค.
- state ๊ตฌ์กฐ๋ฅผ ๋ณ๊ฒฝํ๊ณ ์ถ์ง ์๋ค๋ฉด, Immer ์ฌ์ฉํ ์ ์์ต๋๋ค. ์์ฝ๊ฒ ๋ณ๊ฒฝ ๋ฌธ๋ฒ์ ์ฌ์ฉํ์ฌ ์์ฑํ ์ ์๊ณ ๋ณต์ฌ๋ณธ์ ์์ฑํ์ฌ ์ฒ๋ฆฌํ ์ ์์ต๋๋ค.
๋ค์์ Immer๋ก ๋ค์ ์์ฑํ Art Bucket List ์์์ ๋๋ค.
{ "dependencies": { "immer": "1.7.3", "react": "latest", "react-dom": "latest", "react-scripts": "latest", "use-immer": "0.5.1" }, "scripts": { "start": "react-scripts start", "build": "react-scripts build", "test": "react-scripts test --env=jsdom", "eject": "react-scripts eject" }, "devDependencies": {} }
Immer๋ฅผ ์ฌ์ฉํ๋ฉด artwork.seen = nextSeen
๊ณผ ๊ฐ์ด ๋ณ๊ฒฝํด๋ ๊ด์ฐฎ๋ค๋ ๊ฒ์ ์ ์ํ์ธ์.
updateMyTodos(draft => {
const artwork = draft.find(a => a.id === artworkId);
artwork.seen = nextSeen;
});
์ด๋ ์๋ณธ state๋ฅผ ๋ณ๊ฒฝํ๋ ๊ฒ์ด ์๋๋ผ, Immer์์ ์ ๊ณตํ๋ ํน์ draft
๊ฐ์ฒด๋ฅผ ๋ณ๊ฒฝํ๊ธฐ ๋๋ฌธ์
๋๋ค. ๋ง์ฐฌ๊ฐ์ง๋ก push()
์ pop()
๊ฐ์ ๋ณ๊ฒฝ ํจ์๋ค๋ draft
์ ์ปจํ
์ธ ์ ์ ์ฉํ ์ ์์ต๋๋ค.
๋ด๋ถ์ ์ผ๋ก Immer๋ ํญ์ draft
์์ ์ํํ ๋ณ๊ฒฝ ์ฌํญ์ ๋ฐ๋ผ ์ฒ์๋ถํฐ ๋ค์ state๋ฅผ ๊ตฌ์ฑํฉ๋๋ค. ์ด๋ ๊ฒ ํ๋ฉด state๋ฅผ ๋ณ๊ฒฝํ์ง ์๊ณ ๋ ์ด๋ฒคํธ ํธ๋ค๋ฌ๋ฅผ ๋งค์ฐ ๊ฐ๊ฒฐํ๊ฒ ์ ์งํ ์ ์์ต๋๋ค.
์์ฝ
- ๋ฐฐ์ด์ state๋ก ๋ง๋ค ์ ์์ง๋ง ๋ณ๊ฒฝํ๋ฉด ์๋ฉ๋๋ค.
- ๋ฐฐ์ด์ ๋ณ๊ฒฝํ๋ ๋์ ๋ฐฐ์ด์ ์๋ก์ด ๋ฒ์ ์ ๋ง๋ค๊ณ , state๋ฅผ ์ ๋ฐ์ดํธ ํด์ผํฉ๋๋ค.
[...arr, newItem]
๋ฐฐ์ด ์ ๊ฐ ๊ตฌ๋ฌธ์ ์ฌ์ฉํ์ฌ ์ ํญ๋ชฉ์ ํฌํจํ ๋ฐฐ์ด์ ์์ฑํ ์ ์์ต๋๋ค.filter()
์map()
์ ์ฌ์ฉํ์ฌ ํํฐ๋ง๋ ํญ๋ชฉ๋ค์ด๋ ๋ณํ๋ ํญ๋ชฉ๋ค์ ๊ฐ์ง ๋ฐฐ์ด์ ๋ง๋ค ์ ์์ต๋๋ค.- Immer๋ฅผ ์ฌ์ฉํ์ฌ ์ฝ๋ ๊ฐ๊ฒฐ์ฑ์ ์ ์งํ ์ ์์ต๋๋ค.
์ฑ๋ฆฐ์ง 1 of 4: ์ฅ๋ฐ๊ตฌ๋์ ํญ๋ชฉ ์
๋ฐ์ดํธํ๊ธฐ
โ+โ ๋ฒํผ์ ๋๋ฅด๋ฉด ํด๋น ์ซ์๊ฐ ์ฆ๊ฐํ๋๋ก handleIncreaseClick
๋ก์ง์ ์ฑ์๋ณด์ธ์.
import { useState } from 'react'; const initialProducts = [{ id: 0, name: 'Baklava', count: 1, }, { id: 1, name: 'Cheese', count: 5, }, { id: 2, name: 'Spaghetti', count: 2, }]; export default function ShoppingCart() { const [ products, setProducts ] = useState(initialProducts) function handleIncreaseClick(productId) { } return ( <ul> {products.map(product => ( <li key={product.id}> {product.name} {' '} (<b>{product.count}</b>) <button onClick={() => { handleIncreaseClick(product.id); }}> + </button> </li> ))} </ul> ); }