0%

[React] Mobx-state-tree 학습하기 #11 : 더 많은 mobx-state-tree Types 배우기: map, literal, union, enumeration

이전글 "[React] Mobx-state-tree 학습하기 #10 : Model Definitions Change되면 Hot Module Reloading를 사용하여 Model Tree State 복원하기"에서 이어지는 내용입니다. 참고로 이 포스팅은 제가 학습한 내용을 노트에 정리하듯이 기록하여 올리는 글이기 때문에 보팅 안해주셔서 됩니다. 많은 분들이 코딩에 흥미를 느꼈으면 좋겠습니다. ㅋ





More mobx-state-tree Types: map, literal, union, and enumeration


11번째 레슨입니다. 이번 레슨에서는 그룹 및 사용자의 개념을 소개합니다. 그룹 내에 여러 사용자를 관리할 수 있습니다. 그리고 각 사용자들은 각각의 위시 리스트를 가질 수 ​​있습니다. 또한 union 타입과 타입 discrimination의 강력한 기능을 간단히 살펴볼 것입니다.


우리는 이번 레슨에서 다음을 배우게 됩니다.

  • key로 데이터를 저장하기 위해 type map 사용하기
  • single value types를 생성하기 위해 literals 사용하기
  • type discrimination 하기 위해 literals 과 unions을 Combining 하기
  • quick coding experiments를 위해 Quokka를 scratchpad로 사용하기
  • enumerations 사용하기
  • Enumerations는 literals의 union에 대한 just sugar 이다. 🤔



이제 사용자 그룹을 만들고 각 사용자가 각자의 위시 리스트를 가지도록 모델을 개선해 봅시다.


User 모델 만들기

groups.js 파일을 새로 생성합니다. 그리고 User 모델을 정의 합니다. User 모델은 idname, 그리고 gender 속성을 가집니다.

src/models/Group.js

1
2
3
4
5
6
7
import { types } from 'mobx-state-tree';

const User = types.model({
id: types.string,
name: types.string,
gender: types.union(types.literal('m'), types.literal('f'))
});

타입을 선택할 수 있는 유형을 일반적으로 union이라 합니다. 두 가지 타입을 결합하여 gender을 표현하게 됩니다. 여기서 gender 값은 반드시 m 또는 f 여야합니다.



Quokka 사용하여 빠르게 테스트해보기

VSCode의 익스텐션 프로그램 Quokka를 사용하면 자바스크립트 또는 타입스크립트를 스크래치 패드에서 빠르게 만들고 실행할 수 있습니다.

VSCode에 Quokka 익스텐션을 설치합니다.


그다음 단축키 Cmd + Shift + P를 눌러 Quokka에서 New File를 생성합니다.

위에서 작성한 코드를 Quokka에 복사&붙여넣기 합니다. 그리고 User 모델 인스턴스를 생성하고 genger 속성에 m 또는 f 외에 엉뚱한 값을 넣어보세요. 그럼 다음과 같이 잘못된 타입이라는 에러가 발생합니다.

하지만 gengerm 값을 입력하면 다음과 같이 에러가 발생하지 않습니다.

이제 Man과 Woman 모델을 각각 정의하고, 이 두 모델을 다시 union하여 Human을 정의해봅시다. 그리고 나서 Human 인스턴스를 생성할때 genderm을 입력하여 somebody를 생성합니다. 우리는 somebody가 man인지 아닌지 간단히 확인할 수 있습니다.

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 { types } from 'mobx-state-tree';

const Man = types.model({
id: types.string,
name: types.string,
gender: types.literal('m')
});

const Woman = types.model({
id: types.string,
name: types.string,
gender: types.literal('f')
});

const Human = types.union(Man, Woman);

const someone = Human.create({
id: "123",
name: "michel",
gender: "m"
})

console.log(Man.is(someone))
console.log(Woman.is(someone))

Man.is(someone)true, 그리고 Woman.is(someone)flase가 출력됩니다.



enumeration 사용하기

literal을 union하는 방식인 types.union(types.literal('m'), types.literal('f')) 이 가장 일반적인 패턴입니다. 하지만 더 간단한 표기법이 있습니다. 이를 enumeration이라고 합니다. User 모델의 gender Type을 enumeration를 사용하여 다시 표현하면 types.enumeration("gender", ["m", "f"])가 됩니다.

src/models/Group.js

1
2
3
4
5
6
7
import { types } from 'mobx-state-tree';

export const User = types.model({
id: types.string,
name: types.string,
gender: types.enumeration("gender", ["m", "f"])
});


그다음 User 모델에 wishList 속성을 정의합니다. wishListoptional 이며, 디폴트값은 비어있는 Object {}입니다.

src/models/Group.js

1
2
3
4
5
6
7
8
9
10
11
import { types } from 'mobx-state-tree';

import { WishList } from "./WishList"; // add here

export const User = types.model({
id: types.string,
name: types.string,
gender: types.enumeration("gender", ["m", "f"])

wishList: types.optional(WishList, {}) // add here
});


Group 모델 만들기

이제 Group을 정의 합니다. Group은 User 그룹이라고 할 수 있습니다. 여기에서는 Map를 사용하였습니다. 하지만 우리는 Array를 사용할 수도 있습니다. Group.js 파일 맨 아래에 다음 코드를 입력합니다.

src/models/Group.js

1
2
3
4
5
// ...

export const Group = types.model({
users: types.map(User)
});


다음은 지금까지 작성된 Group.js 파일의 전체 내용입니다.

src/models/Group.js

1
2
3
4
5
6
7
8
9
10
11
12
13
import { types } from "mobx-state-tree";
import { WishList } from "./WishList";

export const User = types.model({
id: types.string,
name: types.string,
gender: types.enumeration("gender", ["m", "f"]),
wishList: types.optional(WishList, {})
});

export const Group = types.model({
users: types.map(User)
});


UI 수정하기

모델을 재구성했으니 이제 UI를 수정해야합니다. index.js 파일을 편집합니다.

Group 모델을 import 합니다. 그리고 간단한 작업을 위해 initialState에는 심슨 가족 데이터 셋트를 미리 준비했습니다.

src/index.js

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
// ...

import { Group } from "./models/Group";

let initialState = {
usres:
"a342": {
id: "a342",
name: "Homer",
gender: "m"
},
"5fc2": {
id: "5fc2",
name: "Marge",
gender: "f"
},
"663b": {
id: "663b",
name: "Bart",
gender: "m"
},
"65aa": {
id: "65aa",
name: "Maggie",
gender: "f"
},
"ba32": {
id: "ba32",
name: "Lisa",
gender: "f"




// ...

let group = Group.create(initialState);

function renderApp() {
ReactDOM.render(<App group={group} />, document.getElementById("root"));


// ...


그다음 선택 박스에서 사용자를 선택하면 위시 리스트 목록, 편집 화면이 보이도록 고쳐보겠습니다. App.js 파일을 수정합니다.

참고로 동영상 강의에서는 group.users.values().map 를 사용하고 있습니다. 하지만 Mobx 2에서 사용방법이 변경되었습니다. Array.from(group.users.values()).map 또는 values(group.users).map 를 사용하세요.

src/components/App.js

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
import React from "react";
import { values } from 'mobx';
import "./App.css";

import WishListView from "./WishListView";

class App extends React.Component
constructor(props) {
super(props);
this.state = {
selectUser: null
};


render() {
const { group } = this.props;
const selectedUser = group.users.get(this.state.selectUser)
return (
<div>
<h1 className="App-title">WishList</h1>

<select onChange={this.onSelectUser}>
<option>- Select user -</option>
{{values(group.users).map(user => (
<option key={user.id} value={user.id}>
{user.name}
</option>
))}
</select>


selectedUser && <WishListView wishList={selectedUser.wishList} />

</div>
);


onSelectUser = event =>
this.setState({
selectUser: event.target.value
})
};


export default App;

실행화면