Избавляемся от бойлерплейта в API-слое
При работе с API часто возникает необходимость описывать запросы к API, обрабатывать ошибки и состояния загрузки. В экосистеме Mobx нет аналога react-query, но базовый функционал можно построить с использованием официального пакета mobx-utils.
Установка
npm i mobx-utils
Использование
import { fromPromise, IPromiseBasedObservable } from 'mobx-utils'
import { makeAutoObservable } from 'mobx'
import { observer } from 'mobx-react-lite'
import { useEffect } from 'react'
type Todo = {
id: number;
title: string;
}
const getTodos = async (): Promise<Todo[]> => {
await new Promise((resolve) => setTimeout(resolve, 500))
return [
{ id: 1, title: 'Clean bathroom' },
{ id: 2, title: 'Feed the cat '},
]
}
class TodoStore {
data?: IPromiseBasedObservable<Todo[]>
constructor() {
makeAutoObservable(this)
}
loadData() {
this.data = fromPromise(getTodos())
}
}
Теперь свойство data
содержит observable
-объект со свойствами state
и value
.
state
принимает значения 'pending' | 'rejected' | 'fulfilled'
. value
принимает значения T | undefined
, где T
- дженерик тип, который автоматически выводится TypeScript'ом на основе того, что передали в функцию fromPromise
.
В компоненте можно по-разному отображать эти данные:
const store = new TodoStore();
const TodoList = observer(() => {
useEffect(() => {
store.loadData();
}, [])
if (store.data?.state === 'pending') {
return <div>Loading...</div>
}
if (store.data?.state === "rejected") {
return <div>Error</div>
}
return <ul>
{store.data?.value.map((todo, i) => {
return <li key={i}>{todo.title}</li>
})}
</ul>
})
Либо через метод case
:
const store = new TodoStore();
const TodoList = observer(() => {
useEffect(() => {
store.loadData();
}, [])
// Без этого ругается TS
if (!store.data) {
return null;
}
return store.data.case({
pending: () => <div>Loading...</div>,
rejected: () => <div>Error</div>,
fulfilled: (value) => <ul>
{value.map((todo, i) => {
return <li key={i}>{todo.title}</li>
})}
</ul>
});
})
Обратите внимание, что во всех примерах корректно работает вывод типов TypeScript для типа Todo
.
Вывод
Библиотеки вроде react-query
предоставляют много дополнительного функционала, например кеш и перезагрузку по фокусу. Но в простых сценариях fromPromise
может сократить бойлерплейт.