상태가 복잡할때 불변성을 유지하면서 업데이를 하게 되면 코드가 복잡해 지고 가독성이 저하 된다. 이때 immer라이브러리를 사용하면 좀 더 쉽게 불변성을 유지하면서 업데이트를 진행할 수 있다. immer라이브러리의 핵심은 불변성을 신경쓰지 않는것 처럼 코드를 작성하되 불변성 관리를 제대로 해주는것이다.
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
|
//Example code
import produce form 'immer';
const originalState = [
{
id: 1,
todo: '1',
checked: true,
},
{
id: 2,
todo: '2',
checked: false,
},
];
//immer는 produce라는 함수를 사용한다
//첫번째 파라미터는 수정하고 싶은 상태
//두번째 파라미터는 상태를 어떻게 업데트 할지 정의하는 함수
const nextState = produce(originalState, (draft) => {
const odo = draft.find((t) => t.id === 2);
todo.checked = true;
draft.push({
id: 3,
todo: '3',
checked: false,
});
draft.splice(draft.findIndex((t) => t.id === 1), 1);
});
|
cs |
다음과 같은 코드가 있다고 해보자
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
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
|
import logo from './logo.svg';
import './App.css';
import React, {useRef, useCallback, useState} from 'react';
const App = () => {
const nextId = useRef(1);
const [form, setForm] = useState({name: '', username: ''});
const [data, setData] = useState({
array: [],
uselessValue: null,
});
//input 수정을 위한 함수
const onChange = useCallback(
(e) => {
const {name, value} = e.target;
setForm({
...form,
[name]: [value]
});
},
[form]
);
//form등록을 위한 함수
const onSubmit = useCallback(
(e) => {
e.preventDefault();
const info = {
id: nextId.current,
name: form.name,
username: form.username,
};
setData({
...data,
array: data.array.concat(info),
});
//form 초기화
setForm({
name: '',
username: '',
});
nextId.current += 1;
},
[data, form.name, form.username]
);
//항목을 삭제하는 함수
const onRemove = useCallback(
(id) => {
setData({
...data,
array: data.array.filter(info => info.id !== id)
});
}, [data]
);
return (
<div>
<form onSubmit={onSubmit}>
<input name={"username"}
placeholder={"ID"}
value={form.username}
onChange={onChange}
/>
<input name={"name"}
plcaeholder={"name"}
value={form.name}
onChange={onChange}
/>
<button type={"submit"}>submit</button>
</form>
<div>
<ul>
{data.array.map((info) => (
<li key={info.id} onClick={() => onRemove(info.id)}>
{info.username} ({info.name})
</li>
))}
</ul>
</div>
</div>
);
}
export default App;
|
cs |
이 코드에 immer를 적용하면 다음과 같이 된다.
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
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
|
import logo from './logo.svg';
import './App.css';
import React, {useRef, useCallback, useState} from 'react';
import produce from 'immer';
const App = () => {
const nextId = useRef(1);
const [form, setForm] = useState({name: '', username: ''});
const [data, setData] = useState({
array: [],
uselessValue: null,
});
//input 수정을 위한 함수
const onChange = useCallback(
(e) => {
const {name, value} = e.target;
setForm(
produce(form, draft => {
draft[name] = value;
})
);
},
[form]
);
//form등록을 위한 함수
const onSubmit = useCallback(
(e) => {
e.preventDefault();
const info = {
id: nextId.current,
name: form.name,
username: form.username,
};
setData(
produce(data, draft => {
draft.array.push(info);
})
);
//form 초기화
setForm({
name: '',
username: '',
});
nextId.current += 1;
},
[data, form.name, form.username]
);
//항목을 삭제하는 함수
const onRemove = useCallback(
(id) => {
setData(
produce(data, draft => {
draft.array.splice(draft.array.findIndex(info => info.id === id));
})
);
}, [data]
);
return (
<div>
//...
</div>
);
}
export default App;
|
cs |
useState의 함수형 업데이트와 immer함께 쓰기
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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
|
import logo from './logo.svg';
import './App.css';
import React, {useRef, useCallback, useState} from 'react';
import produce from 'immer';
const App = () => {
//...
//input 수정을 위한 함수
const onChange = useCallback(
(e) => {
const {name, value} = e.target;
setForm(
produce(draft => {
draft[name] = value;
})
);
},
[form]
);
//form등록을 위한 함수
const onSubmit = useCallback(
(e) => {
//...
setData(
produce(draft => {
draft.array.push(info);
})
);
//form 초기화
setForm({
name: '',
username: '',
});
nextId.current += 1;
},
[data, form.name, form.username]
);
//항목을 삭제하는 함수
const onRemove = useCallback(
(id) => {
setData(
produce(draft => {
draft.array.splice(draft.array.findIndex(info => info.id === id));
})
);
}, [data]
);
return (
<div>
//...
</div>
);
}
export default App;
|
cs |