--- id: update-ko-KR title: 불변성 헬퍼들 permalink: update-ko-KR.html prev: create-fragment-ko-KR.html next: pure-render-mixin-ko-KR.html --- React에서는 mutation을 포함해 어떤 데이터 관리 방식도 사용하실 수 있습니다. 하지만 애플리케이션의 성능이 중요한 부분에서 불변의(immutable) 데이터를 사용할 수 있다면, 쉽게 빠른 `shouldComponentUpdate()` 메소드를 구현해 애플리케이션의 속도를 크게 향상시킬 수 있습니다. JavaScript에서 불변성의 데이터를 다루는 것은 [Clojure](http://clojure.org/)같이 그것을 위해 디자인된 언어로 다루는 것보다는 어렵습니다. 하지만, React는 간단한 불변성 헬퍼를 제공합니다. `update()`는 이런 종류의 데이터를 근본적인 변화 *없이* 쉽게 다루도록 해줍니다. Immutable-js에 관한 좀 더 자세한 정보는 페이스북의 [Immutable-js](https://facebook.github.io/immutable-js/docs/)나 [성능 심화](/react/docs/advanced-performance-ko-KR.html)을 참조하세요. ## 주요 아이디어 만약 데이터를 이렇게 변화시킨다면: ```js myData.x.y.z = 7; // or... myData.a.b.push(9); ``` 이전의 카피가 덮어씌워진다면 어떤 자료가 바뀌었는지 알 방도가 없습니다. 대신에, `myData`의 새로운 카피를 만들고 오직 변화가 필요한 부분만 바꿀 필요가 있습니다. 그 다음 `shouldComponentUpdate()` 에서 `myData`의 이전 카피와 새로운 카피를 `===` 연산자를 사용하여 비교할 수 있습니다. ```js var newData = deepCopy(myData); newData.x.y.z = 7; newData.a.b.push(9); ``` 하지만 깊은 복사는 비싸고, 가끔은 불가능하기도 합니다. 변화가 필요한 객체만 복제하고, 변화가 없는 객체는 다시 사용하는 방법으로만 비용을 줄일 수 있습니다. 안타깝지만 오늘날의 JavaScript에서는 그 방법이 성가실 수 있습니다: ```js var newData = extend(myData, { x: extend(myData.x, { y: extend(myData.x.y, {z: 7}), }), a: extend(myData.a, {b: myData.a.b.concat(9)}) }); ``` 이것은 꽤 성능이 좋긴 하지만 (`log n`개의 객체만 얕은 복사하고, 나머지는 재사용하기 때문에), 일일히 쓰기엔 큰 고통이 따릅니다. 이 반복들을 보세요! 이건 짜증날 뿐만 아니라 버그들을 야기할수도 있습니다. `update()`는 이런 패턴 속에서 코드를 더 쉽게 쓸 수 있도록 편의 문법을 제공합니다. 코드는 이렇습니다: ```js var newData = React.addons.update(myData, { x: {y: {z: {$set: 7}}}, a: {b: {$push: [9]}} }); ``` ([MongoDB 쿼리 언어](http://docs.mongodb.org/manual/core/crud-introduction/#query)에서 영감을 받은) 이 문법에 익숙해지기에는 시간이 조금 걸리긴 하지만, 쓸모 없는 반복이 없고 정적분석이 가능할 뿐더러 변할 수 있는(mutative) 버전보다 더 많은 타이핑이 필요하지도 않습니다. `$`가 앞에 붙어있는 키들은 *커맨드* 라고 불립니다. "변하는" 자료 구조는 *타겟* 이라고 불립니다. ## 사용가능한 커맨드들 * `{$push: array}` 모든 아이템들을 타겟에 있는 `array`에 `push()`합니다. * `{$unshift: array}` 타겟속 `array`에 있는 모든 아이템들을 `unshift()`합니다. * `{$splice: array of arrays}` `arrays` 안의 각 아이템들이 `splice()`를 주어진 인자들을 사용해 호출하게 합니다. * `{$set: any}` 타겟 전체를 대체합니다. * `{$merge: object}` 타겟과 `object`의 키들을 병합합니다. * `{$apply: function}` 는 지금 값을 함수에 전달하고 새로운 리턴 값으로 업데이트합니다. ## 예제 ### 간단한 push ```js var initialArray = [1, 2, 3]; var newArray = update(initialArray, {$push: [4]}); // => [1, 2, 3, 4] ``` `initialArray` 은 여전히 `[1, 2, 3]` 입니다. ### 중첩된 컬렉션 ```js var collection = [1, 2, {a: [12, 17, 15]}]; var newCollection = update(collection, {2: {a: {$splice: [[1, 1, 13, 14]]}}}); // => [1, 2, {a: [12, 13, 14, 15]}] ``` 이것은 `collection`의 인덱스 `2`의 키 `a`에 접근해, 인덱스 `1`에 있는 한 아이템을 접합(splice)해서(`17`를 제거하고) `13`, `14`를 추가합니다. ### 현재 상태에 의거해 값을 업데이트 ```js var obj = {a: 5, b: 3}; var newObj = update(obj, {b: {$apply: function(x) {return x * 2;}}}); // => {a: 5, b: 6} // 위의 것과 같은 동작을 합니다만, 깊게 중첩된 컬렉션들에서는 더 장황해 집니다. var newObj2 = update(obj, {b: {$set: obj.b * 2}}); ``` ### (얕은) 합병 ```js var obj = {a: 5, b: 3}; var newObj = update(obj, {$merge: {b: 6, c: 7}}); // => {a: 5, b: 6, c: 7} ```