이번에는 mobx에서 비동기 액션 처리를 알아보자
가장 쉬운 방법은 액션을 비동기 로직으로 만들지 말고 각각 state를 변하는 액션을 따로따로 만든 다음에 비동기 로직은 container에서 구현하고 단계별로 state를 변경하는 액션은 별도로 분리해서 호출하는 방식이 있다.
두 번째 방식은 액션 안에서 async await 로직을 실행하면서 state를 변경해야 할 때 runinaction 함수로 타이밍마다 state를 변경하는 방식이 있다.
마지막으로는 mobx에서 제공하는 generator를 사용해서 비동기 로직을 처리하는 방식이 있다.
첫 번째 방식
// UserStore 생성
import { action, makeObservable, observable } from "mobx";
export default class UserStore {
@observable
state = {
users: [],
loading: false,
error: null,
};
constructor() {
makeObservable(this);
}
@action
pending() {
this.state.loading = true;
this.state.error = null;
}
@action
success(users) {
this.state.users = users;
this.state.loading = false;
this.state.error = null;
}
@action
fail(error) {
this.state.loading = false;
this.state.error = error;
}
}
// UserListContainer.jsx
import { inject } from "mobx-react";
import { observer } from "mobx-react-lite";
import { useCallback } from "react";
import UserList from "../components/UserList";
const UserListContainer = ({ userStore }) => {
const getUsers = useCallback(() => {}, [userStore]);
return <UserList getUsers={getUsers} />;
};
export default inject("userStore")(observer(UserListContainer));
// UserList.jsx
import { useEffect } from "react";
export default function UserList({ getUsers }) {
useEffect(() => {
getUsers();
}, [getUsers]);
return (
<div>
<ul>users</ul>
</div>
);
}
// App.js
import "./App.css";
import React from "react";
import PersonContainer from "./\\bcontainers/PersonContainer";
import TodoContainer from "./\\bcontainers/TodoContainer";
import TodoFormContainer from "./\\bcontainers/TodoFormContainer";
import UserListContainer from "./\\bcontainers/UserListContainer";
function App() {
return (
<div className="App">
<header className="App-header">
<PersonContainer />
<TodoContainer />
<TodoFormContainer />
<UserListContainer />
</header>
</div>
);
}
export default App;
결과
이제 users 데이터를 store에서 가져와서 UserList에 표현해 보자
// UserListContainer.jsx
import axios from "axios";
import { inject } from "mobx-react";
import { observer } from "mobx-react-lite";
import { useCallback } from "react";
import UserList from "../components/UserList";
const UserListContainer = ({ userStore }) => {
const getUsers = useCallback(async () => {
try {
userStore.pending();
const response = await axios.get("<https://api.github.com/users>");
userStore.success(response.data);
} catch (error) {
userStore.fail(error);
}
}, [userStore]);
const users = userStore.state.users;
return ;
};
export default inject("userStore")(observer(UserListContainer));
// UserList.jsx
import { useEffect } from "react";
export default function UserList({ getUsers, users }) {
useEffect(() => {
getUsers();
}, [getUsers]);
return (
<div>
<ul>
{users.map(user => (
<li>{user.login}</li>
))}
</ul>
</div>
);
}
결과
두 번째 방식인 getUsers를 컨테이너에서 만들지 말고 action으로 만들어서 비동기 처리를 해 보자
// UserStore
import axios from "axios";
import { action, makeObservable, observable, runInAction } from "mobx";
export default class UserStore {
@observable
state = {
users: [],
loading: false,
error: null,
};
constructor() {
makeObservable(this);
}
@action
pending() {
this.state.loading = true;
this.state.error = null;
}
@action
success(users) {
this.state.users = users;
this.state.loading = false;
this.state.error = null;
}
@action
fail(error) {
this.state.loading = false;
this.state.error = error;
}
async getUsers() {
try {
runInAction(() => {
this.state.loading = true;
this.state.error = null;
});
const response = await axios.get("<https://api.github.com/users>");
runInAction(() => {
this.state.users = response.data;
this.state.loading = false;
this.state.error = null;
});
} catch (error) {
runInAction(() => {
this.state.loading = false;
this.state.error = error;
});
}
}
}
// UserListContainer
import { inject } from "mobx-react";
import { observer } from "mobx-react-lite";
import { useCallback } from "react";
import UserList from "../components/UserList";
const UserListContainer = ({ userStore }) => {
const users = userStore.state.users;
const getUsers = useCallback(() => {
userStore.getUsers();
}, [userStore]);
return <UserList getUsers={getUsers} users={users} />;
};
export default inject("userStore")(observer(UserListContainer));
store에 작성하는게 조금 더 깔끔한 것 같다!
마지막 방법인 mobx에서 제공하는 generator를
// UserStore
import axios from "axios";
import { action, flow, makeObservable, observable, runInAction } from "mobx";
export default class UserStore {
@observable
state = {
users: [],
loading: false,
error: null,
};
constructor() {
makeObservable(this);
}
@action
pending() {
this.state.loading = true;
this.state.error = null;
}
@action
success(users) {
this.state.users = users;
this.state.loading = false;
this.state.error = null;
}
@action
fail(error) {
this.state.loading = false;
this.state.error = error;
}
@flow //generator를 비동기 처리해 줄 수 있는 데코레이터
*getUsersFlow() {
//앞에서 *를 달아서 genertor 함수로 만들어준다
try {
this.state.loading = true;
this.state.error = null;
const response = yield axios.get("<https://api.github.com/users>");
this.state.users = response.data;
this.state.loading = false;
this.state.error = null;
} catch (error) {
this.state.loading = false;
this.state.error = error;
}
}
}
// UserListContainer
import { inject } from "mobx-react";
import { observer } from "mobx-react-lite";
import { useCallback } from "react";
import UserList from "../components/UserList";
const UserListContainer = ({ userStore }) => {
const users = userStore.state.users;
const getUsers = useCallback(() => {
userStore.getUsersFlow();
}, [userStore]);
return <UserList getUsers={getUsers} users={users} />;
};
export default inject("userStore")(observer(UserListContainer));
동작은 똑같이 되면서 runInAction 같은 함수를 사용하지 않아도 되기 때문에 어색하더라도 조금 더 편하게 사용할 수 있다.
'Front-End > MobX' 카테고리의 다른 글
stores (0) | 2022.12.16 |
---|---|
@inject 와 Provider (0) | 2022.12.16 |
@action (0) | 2022.12.15 |
@Computed (0) | 2022.12.15 |
@Observer (0) | 2022.12.15 |