Observer에 대해서 알아보자.
Observer는 mobx-react에 있기 때문에 설치부터 해야된다.
npm i mobx-react
Observer는 크게 보면 두 가지 방식으로 쓰일 수 있다.
- observer(<컴포넌트>)
- 데코레이터 없이 사용하는 방식
- 함수처럼 컴포넌트를 실행해서 그 결과물을 사용하는 방식
- 보통 함수 컴포넌트에 사용
- <컴포넌트 클래스>에 가장 위에 @observer 달아서 처리
- 클래스 컴포넌트에 사용
기존에 사용했던 프로젝트에서 App 컴포넌트를 observer 처리를 해 보자
// App.js
import logo from "./logo.svg";
import "./App.css";
import Button from "./components/Button";
import { observer } from "mobx-react";
function App() {
return (
<div className="App">
<header className="App-header">
<img src={logo} className="App-logo" alt="logo" />
<Button />
</header>
</div>
);
}
export default observer(App); // <- observer
App 안에서 관찰하려고 하는 어떤 값들이 들어와 있어야 그 값이 변경됐을 때 다시 렌더를 한다. 지금은 App 컴포넌트 안에 observer 처리된 아이가 들어있지 않기 때문에 어떠한 변경사항도 없다.
index.js에 있는 observer로 처리된 personStore를 export 해서 App.js에서 가져간 다음에 그 안에서 표현을 해 보자.
// index.js
class PersonStore {
@observable
name = "Mark";
@observable
age = 39;
constructor() {
makeObservable(this);
}
plus() {
this.age++;
}
}
export const personStore = new PersonStore();
// App.js
import logo from "./logo.svg";
import "./App.css";
import Button from "./components/Button";
import { observer } from "mobx-react";
import { personStore } from "./index";
function App() {
const click = () => {
personStore.plus();
};
return (
<div className="App">
<header className="App-header">
<img src={logo} className="App-logo" alt="logo" />
<p>
<button onClick={click}>plus</button>
</p>
<p>{personStore.age}</p>
</header>
</div>
);
}
export default observer(App);
이렇게 되면 간단하게 스토어 안에 있는 age의 값을 올리수가 있다. 굉장히 심플해지는게 personStore만 어디선가 전달받으면 이제 렌더를 다시 할 수 있는 로직을 만들 수 있다. personStore를 전달하는 방식은 가장 상위에서 하위로 props로 넘겨주는 방식이 있고 mobx-react에서 제공하는 provider로 context 처리 하면 어디서든 가져다가 사용할 수 있는 방법이 있다. 당연히 후자가 많이 쓰이는 방식이다.
이번에는 자체적으로 만든 context로 사용해 보자.
// contexts/PersonContext.js
import { createContext } from "react";
const PersonContext = createContext();
export default PersonContext;
// index.js
const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(
<React.StrictMode>
<PersonContext.Provider>
<App />
</PersonContext.Provider>
</React.StrictMode>
);
이제 PersonStore을 스토어 폴더로 옮기자
// stores/PersonStore.js
import { makeObservable, observable } from "mobx";
export default class PersonStore {
@observable
name = "Mark";
@observable
age = 39;
constructor() {
makeObservable(this);
}
plus() {
this.age++;
}
}
이제 index.js에서 스토어에 있는 PersonStore 클래스를 import 하고 Provider에 value로 넣어주자
// index.js
const personStore = new PersonStore();
const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(
<React.StrictMode>
<PersonContext.Provider value={personStore}>
<App />
</PersonContext.Provider>
</React.StrictMode>
);
마지막으로 App.js에서 불러오자
import logo from "./logo.svg";
import "./App.css";
import { observer } from "mobx-react";
import { useContext } from "react";
import PersonContext from "./contexts/PersonContext";
function App() {
const personStore = useContext(PersonContext);
const click = () => {
personStore.plus();
};
return (
<div className="App">
<header className="App-header">
<img src={logo} className="App-logo" alt="logo" />
<p>
<button onClick={click}>plus</button>
</p>
<p>{personStore.age}</p>
</header>
</div>
);
}
export default observer(App);
동작이 잘 되는걸 확인 할 수 있다.
전역적으로 주입되는 store를 context로 넣어주고 그 store를 useContext를 이용해서 가져간 다음에 사용을 하게되면 store에 데이터를 변경시켰을 때 store에 값을 사용하고 있는 모든 컴포넌트들이 렌더가 다시 되는 방식이다.
이번에는 함수형을 클래스형으로 바꾸면서 observer를 달아보자
@observer
class App extends React.Component {
static contextType = PersonContext;
@autobind
click() {
const personStore = this.context;
personStore.plus();
}
render() {
const personStore = this.context;
return (
<div className="App">
<header className="App-header">
<img src={logo} className="App-logo" alt="logo" />
<p>
<button onClick={this.click}>plus</button>
</p>
<p>{personStore.age}</p>
</header>
</div>
);
}
}
export default observer(App);
똑같이 작동한다!
'Front-End > MobX' 카테고리의 다른 글
@action (0) | 2022.12.15 |
---|---|
@Computed (0) | 2022.12.15 |
@Observable (0) | 2022.12.15 |
프로젝트에 Decorator 설정하기 (0) | 2022.12.15 |
[MobX] MobX란? (0) | 2022.12.14 |