@astral/mobx-query 0.1.4 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/README.md +323 -0
  2. package/package.json +1 -1
package/README.md CHANGED
@@ -1 +1,324 @@
1
+ # @astral/mobx-query
1
2
 
3
+ Библиотека для кеширования запросов.
4
+
5
+ Особенности:
6
+ - Ориентирована на специфику frontend приложений
7
+ - Для обеспечения реактивности используется [mobx](https://mobx.js.org/)
8
+ - По идеологии использования схожа с [@tanstack/react-query](https://www.npmjs.com/package/@tanstack/react-query/)
9
+ - TS only, totally no `any`
10
+
11
+ ---
12
+
13
+ ## Table of contents
14
+ - [Installation](#installation)
15
+ - [Basic meaning](#basic-meaning)
16
+ - [Варианты использования query](#варианты-использования-query)
17
+ - [Ручной синхронный](#1-ручной-синхронный)
18
+ - [Ручной асинхронный](#2-ручной-асинхронный)
19
+ - [Автоматический](#3-автоматический)
20
+ - [Инвалидация данных](#инвалидация-данных)
21
+ - [Особенности инвалидации](#особенности-инвалидации)
22
+ - [InfiniteQuery](#infinitequery)
23
+ - [isEndReached](#isendreached)
24
+ - [Mutation](#mutation)
25
+ - [Sync вариация](#sync-вариация)
26
+ - [Async вариация](#async-вариация)
27
+ - [Fetch policy](#fetchpolicy)
28
+ - [Вспомогательные флаги и поля](#вспомогательные-флаги-и-поля)
29
+ - [isLoading](#isloading)
30
+ - [isSuccess](#issuccess)
31
+ - [isError](#iserror)
32
+ - [error](#error)
33
+
34
+ # Installation
35
+
36
+ ```shell
37
+ npm i --save @astral/mobx-query
38
+ ```
39
+
40
+ ```shell
41
+ yarn add @astral/mobx-query
42
+ ```
43
+
44
+ ---
45
+
46
+ # Basic meaning
47
+ - executor - исполнитель запроса, который будет совершать запрос. Второй аргумент при создании query
48
+ - enabledAutoFetch - включает автоматический запрос данных при обращении к полю `data`.
49
+ - fetchPolicy - политика, говорящая о том, как следует работать с новыми запросами
50
+ - 'cache-first' - политика применяемая по умолчанию, при отсутствии данных в памяти, будет исполнен executor, его ответ запишется в кеш, и при последующих обращениях данные будут взяты из кеша
51
+ - 'network-only' - каждый запрос будет приводить к вызову executor, его ответ будет записан в кеш(для использования в cache-first)
52
+
53
+ # Basic usage
54
+
55
+ Для начала вам потребуется создать инстанс кеш сервиса
56
+ ```ts
57
+ import { MobxQuery } from '@astral/mobx-query';
58
+
59
+ const mobxQuery = new MobxQuery({
60
+ onError: (error) => {
61
+ console.log(error); // место для вашей обработки ошибок по умолчанию, опционально
62
+ },
63
+ fetchPolicy: 'cache-first', // 'cache-first' по умолчанию, опционально
64
+ enabledAutoFetch: false, // false по умолчанию, опционально
65
+ });
66
+ ```
67
+
68
+ # Варианты использования query
69
+ ## 1. Ручной синхронный.
70
+
71
+ Можно вызывать встроенный метод `sync`, передавая в него колбэк опциональные параметры `onSucess` и `onError`. В onSuccess будут переданы полученные данные от успешного запроса, а в `onError`, соответственно, будет переданы данные ошибки в случае провального запроса.
72
+ Если при вызове обработчик `onError` не был передан, вызовется стандартный, переданный при создании MobxQuery инстанса.
73
+
74
+ ```ts
75
+ const query = mobxQuery.createQuery(
76
+ ['some cache key'],
77
+ () => Promise.resolve('foo'),
78
+ );
79
+
80
+ query.sync({
81
+ onSuccess: (data) => {
82
+ console.log(data); // место для реагирования на ответ
83
+ },
84
+ onError: (error) => {
85
+ console.log(error); // место для вашей ошибки
86
+ }
87
+ });
88
+ ```
89
+
90
+ **[Пример в sandbox](https://codesandbox.io/s/adoring-wing-z8s9ng)**
91
+
92
+ ## 2. Ручной асинхронный.
93
+
94
+ Можно вызвать встроенный метод async. Возвращает промис, соответственно в then попадут данные успешного запроса.
95
+ `Будьте внимательны, используя метод "async", позаботьтесь о добавлении ".catch", иначе ошибка запроса попадет в глобальный exception`.
96
+
97
+ ```ts
98
+ const query = mobxQuery.createQuery(
99
+ ['some cache key'],
100
+ () => Promise.resolve('foo'),
101
+ );
102
+
103
+ query
104
+ .async()
105
+ .then((data) => {
106
+ console.log(data); // место для реагирования на ответ
107
+ })
108
+ .catch((e) => {
109
+ console.log(e); // место для вашей ошибки
110
+ });
111
+ ```
112
+ **[Пример в sandbox](https://codesandbox.io/s/mobx-query-simple-async-k75tfg)**
113
+
114
+ ## 3. Автоматический.
115
+
116
+ При создании query, предусмотрен вариант автоматического запроса при обращении к полю `data` из `query`. Требуется активация флага `enabledAutoFetch` при создании query, либо установка стандартного значения, при создании MobxQuery инстанса.
117
+ Т.е. благодаря реактивности предоставляемой `mobx`, пока не произойдет считывания поля `data` или же не будут вызваны `sync/async` методы, запрос данных так же не произойдет.
118
+
119
+ ```tsx
120
+ import { observer } from 'mobx-react-lite';
121
+
122
+ const query = mobxQuery.createQuery(
123
+ ['some cache key'],
124
+ () => Promise.resolve('foo'),
125
+ { enabledAutoFetch: true }
126
+ );
127
+
128
+ const MyComponent = observer(() => <div>{query.data}</div>) // <div>foo</div>
129
+ ```
130
+ **[Пример в sandbox](https://codesandbox.io/s/happy-cherry-ytqgry)**
131
+
132
+ # Инвалидация данных
133
+ Существует необходимость инвалидировать данные, типичным примером являются [CRUD операции](https://ru.wikipedia.org/wiki/CRUD).
134
+ В контексте нашей библиотеки, инвалидация подразумевает под собой отметку для query, означающую, что данные устарели, и их необходимо обновить.
135
+ Для корректной работы инвалидации, при создании query требуется использование `ключа`.
136
+ Ключ для создания может быть как примитивом, так и объектом. Главное, чтобы они были подходящими для JSON сериализации.
137
+
138
+ Инстанс MobxQuery содержит специальный метод `invalidate`, принимающий в качестве аргумента `массив ключей`.
139
+
140
+ ```ts
141
+ const query = mobxQuery.createQuery(
142
+ ['some cache key'],
143
+ () => Promise.resolve('foo'),
144
+ { enabledAutoFetch: true }
145
+ );
146
+
147
+ mobxQuery.invalidate(['some cache key'])
148
+ ```
149
+
150
+ **[Пример в sandbox](https://codesandbox.io/s/mobx-query-invalidate-query-hhcngr)**
151
+
152
+ ## Особенности инвалидации
153
+ - Как при создании query, так и при инвалидации, нужно использовать массив ключей. Предполагается, что query может быть инвалидирован по нескольким ключам
154
+ ```ts
155
+ const query = mobxQuery.createQuery(
156
+ ['key one', 'key two'], // ключ - массив строк
157
+ () => Promise.resolve('foo'),
158
+ { enabledAutoFetch: true }
159
+ );
160
+
161
+ mobxQuery.invalidate(['key two']); // query будет инвалидирован
162
+ mobxQuery.invalidate(['key one']); // query будет инвалидирован
163
+ ```
164
+ Но, стоит учитывать, что ключом является цельный элемент массива, а не составляющие элемента
165
+ ```ts
166
+ const query = mobxQuery.createQuery(
167
+ [['key one', 'key two']], // ключ - двумерный массив строк
168
+ () => Promise.resolve('foo'),
169
+ { enabledAutoFetch: true }
170
+ );
171
+
172
+ mobxQuery.invalidate(['key one']); // ключ не совпадает, query НЕ будет инвалидирован
173
+ ```
174
+
175
+ - Инвалидация будет происходить только для query, поле `data` которых считывается в данный момент. Для query, `data` которых будут отрендерены позже, запрос произойдет только в момент использования. Для превентивного обновления данных потребуется последовательное использование `sync/async` методов сразу после `invalidate`.
176
+
177
+ # InfiniteQuery
178
+ Существует необходимость постепенного запроса массивов данных, в постраничном режиме. Типичный пример, инфинити скролл, когда новая пачка данных запрашивается, в момент когда пользователь докрутил список до конца.
179
+ Для удобства, мы создали специальный `query`, который содержит дополнительный метод `fetchMore` и при вызове оного, происходит запрос с увеличенными счетчиками. Данные ответа на этот запрос, будут сконкатенированы с уже имеющимся. В случае, если количество данных меньше, чем длина страницы, будет считаться что мы дошли до конца списка.
180
+ В `executor` будет передан объект с `offset` - количество элементов отступа от начала списка, и `count` - количество элементов на одну страницу.
181
+
182
+ Значение `count` и увеличение `offset` регулируется опциональным параметром `incrementCount` при создании `query`. По умолчанию равен `30`.
183
+
184
+ ```ts
185
+ import { when } from 'mobx';
186
+
187
+ const query = mobxQuery.createInfiniteQuery(
188
+ ['some cache key'],
189
+ ({ offset, count }) => {
190
+ // можно использовать "offset/count" для необходимых преобразований и последующего запроса к api
191
+ return Promise.resolve(['foo'])
192
+ },
193
+ {
194
+ incrementCount: 30, // опционально, по умолчанию 30
195
+ }
196
+ );
197
+
198
+ await query.async();
199
+
200
+ console.log(query.data); // ['foo']
201
+
202
+ query.fetchMore();
203
+ await when(() => !query.isLoading); // ждем фоновой загрузки
204
+
205
+ console.log(query.data); // ['foo', 'foo']
206
+ ```
207
+ ## isEndReached
208
+ Для определения того, что мы все таки достигли конца списка, присутствует флаг `isEndReached`.
209
+
210
+ ```ts
211
+ const query = mobxQuery.createInfiniteQuery(
212
+ ['some cache key'],
213
+ () => Promise.resolve([]),
214
+ );
215
+
216
+ await query.async();
217
+
218
+ console.log(query.isEndReached); // true
219
+ ```
220
+
221
+ **[Пример в sandbox](https://codesandbox.io/s/mobx-query-infinityquery-sdcc6g)**
222
+
223
+ # Mutation
224
+ Для изменения данных необходимо использовать mutation. Ответы Mutation не кэшируются.
225
+
226
+ ```ts
227
+ const mutation = mobxQuery.createMutation(
228
+ (params) => {
229
+ console.log(params); // при необходмости, можем использовать опциональные параметры
230
+ return Promise.resolve('foo');
231
+ },
232
+ );
233
+ ```
234
+ **[Пример в sandbox](https://codesandbox.io/s/mobx-query-mutation-p2pnct)**
235
+
236
+ ## async вариация
237
+ ```ts
238
+ mutation
239
+ .async('bar') // тут, по нашему примеру, увидим консоль 'bar'
240
+ .then((data) => {
241
+ console.log(data) // а тут уже 'foo'
242
+ });
243
+ ```
244
+
245
+ ## sync вариация
246
+ ```ts
247
+ mutation.sync({
248
+ params: 'bar',
249
+ onSuccess: (data) => {
250
+ console.log(data) // а тут уже 'foo'
251
+ }
252
+ }); // тут, по нашему примеру, увидим консоль 'bar'
253
+ ```
254
+
255
+ # fetchPolicy
256
+
257
+ ```ts
258
+ const cacheFirstQuery = mobxQuery.createQuery(
259
+ ['cache-first key'],
260
+ () => {
261
+ console.log('cache-first request');
262
+ return Promise.resolve('foo');
263
+ },
264
+ {
265
+ fetchPolicy: 'cache-first',
266
+ }
267
+ );
268
+
269
+ const networkOnlyQuery = mobxQuery.createQuery(
270
+ ['network-only key'],
271
+ () => {
272
+ console.log('network-only request');
273
+ return Promise.resolve('bar');
274
+ },
275
+ {
276
+ fetchPolicy: 'network-only',
277
+ }
278
+ );
279
+
280
+ await cacheFirstQuery.async(); // увидим консоль 'cache-first request'
281
+ await networkOnlyQuery.async(); // увидим консоль 'network-only request'
282
+
283
+ await cacheFirstQuery.async(); // вызова executor не произойдет, и консоль не выведется
284
+ await networkOnlyQuery.async(); // вновь увидим консоль 'network-only request'
285
+
286
+ const duplicateCacheFirstQuery = mobxQuery.createQuery(
287
+ ['cache-first key'], // использован тот же самый ключ, что и для cacheFirstQuery
288
+ () => {
289
+ console.log('duplicate cache-first request');
290
+ return Promise.resolve('foo');
291
+ }
292
+ );
293
+
294
+ await duplicateCacheFirstQuery.async(); // вызова executor не произойдет, и консоль не выведется
295
+ ```
296
+ **[Пример в sandbox](https://codesandbox.io/s/mobx-query-fetchpolicy-wvh8jl)**
297
+
298
+ # Вспомогательные флаги и поля
299
+ `Query`, `InfiniteQuery` и `Mutation` имеют одинаковый набор вспомогательных флагов и полей, работающих по единому принципу.
300
+
301
+ ## isLoading
302
+ Boolean флаг, указывающий на процесс выполнения запроса
303
+ ## isSuccess
304
+ Boolean флаг, указывающий на успешное выполнение запроса
305
+ ## isError
306
+ Boolean флаг, указывающий на провалившийся запрос
307
+ ## error
308
+ Поле, содержащее информацию о последней ошибке
309
+
310
+ ```ts
311
+ const query = mobxQuery.createQuery(
312
+ ['some cache key'],
313
+ () => Promise.reject('foo'),
314
+ );
315
+
316
+ await query
317
+ .async()
318
+ .catch((e) => {
319
+ console.log(e); // 'foo'
320
+ });
321
+
322
+ console.log(query.isError); // 'true'
323
+ console.log(query.error); // 'foo'
324
+ ```
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@astral/mobx-query",
3
- "version": "0.1.4",
3
+ "version": "1.0.0",
4
4
  "browser": "./index.js",
5
5
  "main": "./index.js",
6
6
  "dependencies": {