immutable๊ณผ immer

July 12, 2021 · 15 mins read label-icon React Javascript

immutable์™€ immer

  • ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ์˜ ๋ถˆ๋ณ€์„ฑ์„ ์œ ์ง€ํ•  ๋•Œ ๊ฐ„ํŽธํ•˜๊ฒŒ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ

immutable

  • immutable ๊ณต์‹ ๋ฌธ์„œ
  • Map, List, set, get, update, setIn, getIn, updateIn, toJS, Record ๋“ฑ์„ ์‚ฌ์šฉํ•œ๋‹ค.
  • ์ผ๋ฐ˜ ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ๋กœ ๋ณ€ํ™˜ํ•  ๊ฒฝ์šฐ toJS()๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค
  • ๊ธธ์ด๊ฐ’์€ length ๋Œ€์‹  size๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค.
  • isEmpty()๋กœ ๋นˆ ๊ฐ’ ์—ฌ๋ถ€๋ฅผ boolean์œผ๋กœ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค.

์„ค์น˜

1
npm i immutable

Map

  • ๊ฐ์ฒด๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒฝ์šฐ ์‚ฌ์šฉํ•œ๋‹ค.
  • ๊ฐ์ฒด๊ฐ€ ๋ณต์žกํ•œ ๊ฒฝ์šฐ fromJS()๋ฅผ ์‚ฌ์šฉํ•ด์„œ ์ฒ˜๋ฆฌํ•  ์ˆ˜๋„ ์žˆ๋‹ค.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
import { Map, fromJS } from 'immutable';

const obj1 = Map({
  foo: 1,
  inner: Map({
    bar: 10
  })
});

const obj2 = fromJS({
  foo: 1,
  inner: { // Map์„ ์‚ฌ์šฉํ•˜์ง€ ์•Š์•˜์Œ
    bar: 10
  }
});

console.log(obj1); // Map {foo: 1, inner: Map, constructor: Object}
console.log(obj2); // Map {foo: 1, inner: Map, constructor: Object}
console.log(obj1.toJS()) // {foo: 1, inner: Object}
console.log(obj.size) // 2
console.log(obj.isEmpty()) // false

List

  • ๋ฐฐ์—ด์„ ์‚ฌ์šฉํ•˜๋Š” ๊ฒฝ์šฐ ์‚ฌ์šฉํ•œ๋‹ค.
1
2
3
4
5
6
7
8
9
10
11
12
import { List } from 'immutable';

const arr = List([
  Map({ foo: 1 }),
  Map({ bar: 2 }),
]);


console.log(arr); // List {size: 2, _origin: 0, _capacity: 2, _level: 5, _root: nullโ€ฆ}
console.log(arr.toJS()); // [Object, Object]
console.log(arr.size) // 2
console.log(arr.isEmpty()) // false

set

  • ๊ฐ’์„ ์„ค์ •ํ•˜๋Š” ๊ฒฝ์šฐ ์‚ฌ์šฉํ•œ๋‹ค.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import { Map, List } from 'immutable';

const obj = Map({
  foo: 1,
  inner: Map({
    bar: 10
  })
});

const arr = List([
  Map({ foo: 1 }),
  Map({ bar: 2 }),
]);


const newObj = obj.set('foo',5)
const newArr = arr.set(0, 5)
console.log(newObj.toJS());  // {foo: 5, inner: Object}
console.log(newArr.toJS()); // [5, Object]

get

  • ๊ฐ’์„ ์ฝ์„ ๊ฒฝ์šฐ ์‚ฌ์šฉํ•œ๋‹ค.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import { Map, List } from 'immutable';

const obj = Map({
  foo: 1,
  inner: Map({
    bar: 10
  })
});

const arr = List([
  Map({ foo: 1 }),
  Map({ bar: 2 }),
]);


console.log(obj.get('foo')); // 1
console.log(arr.get(1).toJS()); // { bar: 2 }

update

  • ๊ฐ’์„ ์ฝ์€ ๋’ค ์„ค์ •ํ•  ๋•Œ ์‚ฌ์šฉํ•œ๋‹ค.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import { Map, List } from 'immutable';

const obj = Map({
  foo: 1,
  inner: Map({
    bar: 10
  })
});

const arr = List([
  Map({ foo: 1 }),
  Map({ bar: 2 }),
]);


const newObj = obj.update('foo', value => value + 10 )
console.log(newObj.toJS()) // {foo: 11, inner: Object}

setIn, getIn, updateIn

  • ๋‚ด๋ถ€์— ์žˆ๋Š” ๊ฐ’์„ set, get, updateํ•˜๋Š” ๊ฒฝ์šฐ ์‚ฌ์šฉํ•œ๋‹ค.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
import { Map, List } from 'immutable';

const obj = Map({
  foo: 1,
  inner: Map({
    bar: 10
  })
});

const arr = List([
  Map({ foo: 1 }),
  Map({ bar: 2 }),
]);


const newObj = obj.setIn(['inner', 'bar'], 20)
console.log(newObj.toJS()) // {foo: 1, inner: { bar : 20 }}
console.log(newObj.getIn(['inner', 'bar'])) // 20
console.log(newObj.updateIn(["inner", "bar"], value => value + 5).toJS()) // {foo: 1, inner: { bar : 25 }}

const newArr = arr.setIn([0, 'foo'], 30)
console.log(newArr.toJS()) // [{foo : 30}, {bar: 2}]
console.log(newArr.getIn([0, 'foo'])) // 30
console.log(newArr.updateIn([0, "foo"], value => value + 10).toJS()); // [{foo : 40}, {bar: 2}]

delete

  • key๊ฐ’์„ ์ œ๊ฑฐํ•˜๋Š” ๊ฒฝ์šฐ ์‚ฌ์šฉํ•œ๋‹ค.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
import { Map, List } from 'immutable';

const obj = Map({
  foo: 1,
  inner: Map({
    bar: 10
  })
});

const arr = List([
  Map({ foo: 1 }),
  Map({ bar: 2 }),
]);


const newObj = obj.delete('foo');
console.log('newObj',newObj.toJS()) // {inner: Object}

const newArr = arr.delete(0) 
console.log('newArr',newArr.toJS()) // [{bar: 2}]

Record

  • get์ด๋‚˜ getIn์„ ์‚ฌ์šฉํ•˜์ง€ ์•Š๊ณ  ๊ฐ’์„ ์ฝ์„ ์ˆ˜ ์žˆ๋‹ค.
  • ์ผ๋ฐ˜ ๊ฐ์ฒด์˜ ๊ฐ’์„ ๊ฐ€์ ธ์˜ค๋Š” ๋ฐฉ์‹์œผ๋กœ ๊ฐ’์„ ๊ฐ€์ ธ์˜ฌ ์ˆ˜ ์žˆ๋‹ค. (obj.name)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
import { Record } from 'immutable';

const Person = Record({
  name: 'ํ™๊ธธ๋™',
  age: 1
});

let person = Person();

// (1)
console.log(person.name) // ํ™๊ธธ๋™

// (2)
person = person.set('age', 5)
console.log(person.age) // 5
// person.name = '์ฒ ์ˆ˜' (Error : Cannot set on an immutable record)

// (3)
person = Person({
  name: '์˜ํฌ',
  age: 10,
});
const { name, age } = person;
console.log(name, age) // ์˜ํฌ 10

// (4)
const dog = Record({
  name: '๋ฉ๋ฉ์ด',
  age: 1,
  foo: Record({
    bar: true
  })() // (*)
})() // (*)
console.log(dog.name) // ๋ฉ๋ฉ์ด
console.log(dog.foo.bar) // true

immer.js

  • immer ๊ณต์‹ ๋ฌธ์„œ
  • immutable.js๋ณด๋‹ค ๋”์šฑ ๊ฐ„ํŽธํ•˜๊ฒŒ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.
  • ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ์˜ Proxy๊ธฐ๋Šฅ์„ ์‚ฌ์šฉํ•œ๋‹ค.

์„ค์น˜

1
npm i immer

produce

  • immer๋ฅผ ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•ด์„œ ๋ณดํ†ต produce๋ผ๋Š” ์ด๋ฆ„์œผ๋กœ ๋ถˆ๋Ÿฌ์˜จ๋‹ค.
  • produceํ•จ์ˆ˜์˜ ์ฒซ ๋ฒˆ์งธ ์ธ์ž์—๋Š” ๊ธฐ์กด์˜ ๊ฐ์ฒด๋ฅผ, ๋‘ ๋ฒˆ์งธ ์ธ์ž์—๋Š” ์—…๋ฐ์ดํŠธ๋ฅผ ์‹คํ–‰ํ•˜๋Š” ํ•จ์ˆ˜๊ฐ€ ๋“ค์–ด๊ฐ„๋‹ค.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
import produce from "immer";

const memo = [
  { idx: 1, title: "์ œ๋ชฉ 1", isTrash: false },
  { idx: 2, title: "์ œ๋ชฉ 2", isTrash: true }
];

// ์ฝ๊ธฐ
console.log(memo[0].idx); // 1

// ์ถ”๊ฐ€
const addMemo = produce(memo, (draft) => {
  draft.push({
    idx: 3,
    title: "์ œ๋ชฉ 3",
    isTrash: true
  });
});
console.log(addMemo[2]); // {idx: 3, title: "์ œ๋ชฉ 3", isTrash: true}

// ์ˆ˜์ •
const updateMemo = produce(memo, (draft) => {
  draft[1].title = "์ œ๋ชฉ ๋ณ€๊ฒฝ!";
});
console.log(updateMemo[1].title); // ์ œ๋ชฉ ๋ณ€๊ฒฝ!

// ์‚ญ์ œ
const deleteMemo = produce(memo, (draft) => {
  draft.pop();
});
console.log(deleteMemo); // [{idx: 1, title: "์ œ๋ชฉ 1", isTrash: false}]

๊ธฐํƒ€

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

์ฐธ๊ณ 

https://immutable-js.com/
https://immerjs.github.io/immer/
https://velopert.com/3486
https://react.vlpt.us/basic/23-immer.html