MobX
-
immer가 기본적으로 적용되있다고 보면 된다.
-
redux보다 더 간결함.
-
state가 있으면 action은 state를 변경한다. 끝!
ex)
observable(state) -----> observer { naem: ‘zero’,
age: 26,
married: false }↑↓
[action] state.name = ‘nero’
—> state가 있고, state를 observable이 감싸고 있고, state를 편하게 객체 값을 바꾸듯이 바꿀 때마다, observable들이 observer들한테 알려준다.
const { observable, autorun, reaction, action, runInAction } = require('mobx');
// redux의 initialState 부분
const state = observable({
compA: 'a',
compB: 12,
compC: null,
});
// 리덕스는 리듀서가 필수이기 때문에, 리듀서를 연결하기 위해 사용
// Mobx는 state를 observable로 감싸면 끝!
// const store = createStore(reducer, initialState);
// observable state가 바뀔 때마다 autorun 안의 콜백함수를 실행 (state 변경 감지기)
autorun(() => {
console.log('changed');
});
// (state 변경 감지기) 첫 번째 인수인 함수의 리턴하는 값이 변경되었을 때만 실행 (compB가 변경될때만 실행)
reaction(() => {
return state.compB;
}, () => {
console.log('reaction', state.compB);
});
// redux의 액션 생성, dispatch 다 필요 없고, MobX는 객체처럼 바로 변경 가능
state.compA = 'b';
state.compB = 'c';
state.compC = 'c';
// Mobx는 3개의 액션을 일련의 하나의 액션으로 취급해서 'changed'가 한번만 출력됨
runInAction(() => {
state.compA = 'b';
state.compB = 'c';
state.compC = 'c';
}); // 이게 하나의 액션이야!! 안써도 무방!
action과 runInAction은 유사한 관계가 있음.
- action은 함수처럼 따로 생성해놓고, 필요할 때 호출
- runInAction은 바로 실행
// 필요할 때 실행
const change = action(() => {
state.compA = 'c';
state.compB = 25;
state.compC = 'c';
});
// 바로 실행
runInAction(() => {
state.compA = 'c';
state.compB = 25;
state.compC = 'c';
});
observable로 묶는다면 state 그룹 선언 가능
cf) redux는 initialState 안에 하나의 큰 객체({}) 안에 state들이 존재
const userState = observable({
isLoggingIn: true,
data: null,
});
const postState = observable([]);
postState.push({ id: 1, content: '안녕하세요.' });
userState.data = {
id: 1,
nickname: 'zerocho',
};
로그인을 하면서 동시에 글을 작성하고 싶은 경우
runInAction(() => {
postState.push({ id: 1, content: '안녕하세요.' });
userState.data = {
id: 1,
nickname: 'zerocho',
};
});
redux 같은 경우엔, user와 post가 분리하여 생성하기 때문에 위의 작업을 동시에 진행하기 위해서는 액션을 두 개 생성하여 동시에 실행시켜야 한다.
reducer 사이를 넘나들며 데이터(state)를 변경하기 매우 힘들다.
class로 Mobx 사용하기
class UserStore {
state = observable({
name: 'zerocho',
age: 26,
});
@action
changeName(value) {
this.state.name = value;
}
}
const userStore = new UserStore(); // 싱글턴
class를 사용하는 이유는 ????? —> 새로운 인스턴스(new)를 여러개 찍어내기 위해 사용
UserStore를 2번 인스턴스를 생성해서 만들 필요 없다고 생각. 클라이언트(프론트)에선 한 명의 사용자가 로그아웃 하기 전까진, 다른 사용자가 로그인할 수 없기 때문에.
아래는 위의 class로 선언한 것을 함수형으로 구현했을 때,
const userState = observable({
name: 'zerocho',
age: 26,
changeName(value) {
this.name = value;
}
});
참고
- 인프런 강의 (zerocho)