@dxtmisha/wiki 0.24.0 → 0.24.1
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.
- package/package.json +1 -1
- package/src/media/functional/en/about.mdx +55 -0
- package/src/media/functional/en/dataStorage.mdx +61 -83
- package/src/media/functional/en/useApiRef.mdx +517 -0
- package/src/media/functional/en/useBroadcastValueRef.mdx +344 -0
- package/src/media/functional/en/useCookieRef.mdx +348 -0
- package/src/media/functional/en/useGeoIntlRef.mdx +288 -0
- package/src/media/functional/en/useHashRef.mdx +302 -0
- package/src/media/functional/en/useLazyRef.mdx +329 -0
- package/src/media/functional/en/useLoadingRef.mdx +159 -0
- package/src/media/functional/en/useSessionRef.mdx +248 -0
- package/src/media/functional/en/useStorageRef.mdx +242 -0
- package/src/media/functional/en/useTranslateRef.mdx +312 -0
- package/src/media/functional/ru/about.mdx +55 -0
- package/src/media/functional/ru/dataStorage.mdx +59 -81
- package/src/media/functional/ru/useApiRef.mdx +517 -0
- package/src/media/functional/ru/useBroadcastValueRef.mdx +344 -0
- package/src/media/functional/ru/useCookieRef.mdx +348 -0
- package/src/media/functional/ru/useGeoIntlRef.mdx +288 -0
- package/src/media/functional/ru/useHashRef.mdx +302 -0
- package/src/media/functional/ru/useLazyRef.mdx +329 -0
- package/src/media/functional/ru/useLoadingRef.mdx +159 -0
- package/src/media/functional/ru/useSessionRef.mdx +248 -0
- package/src/media/functional/ru/useStorageRef.mdx +242 -0
- package/src/media/functional/ru/useTranslateRef.mdx +312 -0
|
@@ -0,0 +1,517 @@
|
|
|
1
|
+
import {Meta} from '@storybook/addon-docs/blocks'
|
|
2
|
+
|
|
3
|
+
<Meta title='@dxtmisha/functional/ru/Composables/useApiRef'/>
|
|
4
|
+
|
|
5
|
+
# Композабл useApiRef
|
|
6
|
+
|
|
7
|
+
Композабл для работы с HTTP-запросами в Vue 3 приложениях. Предоставляет реактивный интерфейс для выполнения API запросов с автоматическим управлением состоянием загрузки, поддержкой реактивности параметров, условным выполнением и трансформацией данных.
|
|
8
|
+
|
|
9
|
+
## Основные возможности
|
|
10
|
+
|
|
11
|
+
- **Реактивные запросы** — автоматическое выполнение запросов при изменении параметров
|
|
12
|
+
- **Управление состоянием** — автоматическое отслеживание состояния загрузки и готовности данных
|
|
13
|
+
- **Условное выполнение** — возможность выполнять запросы только при выполнении условий
|
|
14
|
+
- **Трансформация данных** — преобразование полученных данных перед сохранением
|
|
15
|
+
- **Интеграция с Api** — использует класс Api для выполнения запросов с поддержкой кеширования
|
|
16
|
+
- **Глобальные условия** — возможность установить глобальные условия для всех useApiRef
|
|
17
|
+
- **Автоочистка** — опциональная очистка данных при размонтировании компонента
|
|
18
|
+
- **TypeScript поддержка** — полная типизация с дженериками
|
|
19
|
+
|
|
20
|
+
## Базовое использование
|
|
21
|
+
|
|
22
|
+
### Простой GET запрос
|
|
23
|
+
|
|
24
|
+
```javascript
|
|
25
|
+
import { useApiRef } from '@dxtmisha/functional'
|
|
26
|
+
|
|
27
|
+
// Выполняет GET запрос при монтировании компонента
|
|
28
|
+
const { data, loading, isStarting, reading } = useApiRef('/api/users')
|
|
29
|
+
|
|
30
|
+
// data - ref с данными ответа
|
|
31
|
+
// loading - ref с состоянием загрузки
|
|
32
|
+
// isStarting - computed, true до первой загрузки данных
|
|
33
|
+
// reading - computed, true во время чтения данных
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
### Использование в компоненте
|
|
37
|
+
|
|
38
|
+
```vue
|
|
39
|
+
<script setup>
|
|
40
|
+
import { useApiRef } from '@dxtmisha/functional'
|
|
41
|
+
|
|
42
|
+
const { data: users, loading } = useApiRef('/api/users')
|
|
43
|
+
</script>
|
|
44
|
+
|
|
45
|
+
<template>
|
|
46
|
+
<div v-if="loading">Загрузка...</div>
|
|
47
|
+
<div v-else-if="users">
|
|
48
|
+
<div v-for="user in users" :key="user.id">
|
|
49
|
+
{{ user.name }}
|
|
50
|
+
</div>
|
|
51
|
+
</div>
|
|
52
|
+
</template>
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
## Параметры
|
|
56
|
+
|
|
57
|
+
### `path`
|
|
58
|
+
|
|
59
|
+
Путь к API endpoint. Может быть строкой или ref-ом для реактивности.
|
|
60
|
+
|
|
61
|
+
**Тип:** `RefOrNormal<string | undefined>`
|
|
62
|
+
|
|
63
|
+
```javascript
|
|
64
|
+
// Статический путь
|
|
65
|
+
const { data } = useApiRef('/api/users')
|
|
66
|
+
|
|
67
|
+
// Реактивный путь
|
|
68
|
+
const userId = ref(1)
|
|
69
|
+
const { data: user } = useApiRef(computed(() => `/api/users/${userId.value}`))
|
|
70
|
+
|
|
71
|
+
// При изменении userId автоматически выполняется новый запрос
|
|
72
|
+
userId.value = 2
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
### `options`
|
|
76
|
+
|
|
77
|
+
Параметры запроса. Может быть HTTP методом, объектом настроек или ref-ом.
|
|
78
|
+
|
|
79
|
+
**Тип:** `ApiMethodItem | RefOrNormal<ApiFetch>`
|
|
80
|
+
|
|
81
|
+
```javascript
|
|
82
|
+
// Указать только метод
|
|
83
|
+
const { data } = useApiRef('/api/users', 'POST')
|
|
84
|
+
|
|
85
|
+
// Полные настройки
|
|
86
|
+
const { data } = useApiRef('/api/users', {
|
|
87
|
+
method: 'POST',
|
|
88
|
+
request: { name: 'Иван', email: 'ivan@example.com' },
|
|
89
|
+
headers: { 'Content-Type': 'application/json' }
|
|
90
|
+
})
|
|
91
|
+
|
|
92
|
+
// Реактивные параметры
|
|
93
|
+
const params = ref({ page: 1, limit: 10 })
|
|
94
|
+
const { data } = useApiRef('/api/users', computed(() => ({
|
|
95
|
+
method: 'GET',
|
|
96
|
+
request: params.value
|
|
97
|
+
})))
|
|
98
|
+
|
|
99
|
+
// При изменении params автоматически выполняется новый запрос
|
|
100
|
+
params.value = { page: 2, limit: 10 }
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
### `reactivity`
|
|
104
|
+
|
|
105
|
+
Включить или отключить автоматическое выполнение при изменении параметров.
|
|
106
|
+
|
|
107
|
+
**Тип:** `boolean`
|
|
108
|
+
**По умолчанию:** `true`
|
|
109
|
+
|
|
110
|
+
```javascript
|
|
111
|
+
// С реактивностью (по умолчанию)
|
|
112
|
+
const params = ref({ page: 1 })
|
|
113
|
+
const { data, reset } = useApiRef('/api/users', { request: params }, true)
|
|
114
|
+
|
|
115
|
+
params.value.page = 2 // Автоматически выполнится запрос
|
|
116
|
+
|
|
117
|
+
// Без реактивности
|
|
118
|
+
const { data, reset } = useApiRef('/api/users', { request: params }, false)
|
|
119
|
+
|
|
120
|
+
params.value.page = 2 // Запрос НЕ выполнится
|
|
121
|
+
await reset() // Нужно вызвать reset вручную
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
### `conditions`
|
|
125
|
+
|
|
126
|
+
Условие для выполнения запроса. Запрос выполняется только если условие истинно.
|
|
127
|
+
|
|
128
|
+
**Тип:** `RefType<boolean>`
|
|
129
|
+
|
|
130
|
+
```javascript
|
|
131
|
+
// Запрос выполняется только когда isAuth === true
|
|
132
|
+
const isAuth = ref(false)
|
|
133
|
+
const { data } = useApiRef('/api/profile', undefined, true, isAuth)
|
|
134
|
+
|
|
135
|
+
// data будет undefined, пока isAuth === false
|
|
136
|
+
console.log(data.value) // undefined
|
|
137
|
+
|
|
138
|
+
isAuth.value = true // Запрос автоматически выполнится
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
### `transformation`
|
|
142
|
+
|
|
143
|
+
Функция для преобразования полученных данных перед сохранением в ref.
|
|
144
|
+
|
|
145
|
+
**Тип:** `(data: T) => R`
|
|
146
|
+
|
|
147
|
+
```javascript
|
|
148
|
+
// Преобразование данных API в нужный формат
|
|
149
|
+
const { data } = useApiRef(
|
|
150
|
+
'/api/users',
|
|
151
|
+
undefined,
|
|
152
|
+
true,
|
|
153
|
+
undefined,
|
|
154
|
+
(response) => {
|
|
155
|
+
// response - данные от API
|
|
156
|
+
// Возвращаем преобразованные данные
|
|
157
|
+
return response.data.map(user => ({
|
|
158
|
+
id: user.id,
|
|
159
|
+
fullName: `${user.firstName} ${user.lastName}`,
|
|
160
|
+
isActive: user.status === 'active'
|
|
161
|
+
}))
|
|
162
|
+
}
|
|
163
|
+
)
|
|
164
|
+
|
|
165
|
+
// data содержит преобразованные данные
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
### `unmounted`
|
|
169
|
+
|
|
170
|
+
Очищать ли данные при размонтировании компонента.
|
|
171
|
+
|
|
172
|
+
**Тип:** `boolean`
|
|
173
|
+
**По умолчанию:** `undefined`
|
|
174
|
+
|
|
175
|
+
```javascript
|
|
176
|
+
// Данные будут очищены при размонтировании компонента
|
|
177
|
+
const { data } = useApiRef('/api/users', undefined, true, undefined, undefined, true)
|
|
178
|
+
|
|
179
|
+
// При переходе на другую страницу data станет undefined
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
## Возвращаемые значения
|
|
183
|
+
|
|
184
|
+
### `data`
|
|
185
|
+
|
|
186
|
+
Ref с данными ответа. `undefined` до первой загрузки.
|
|
187
|
+
|
|
188
|
+
**Тип:** `Ref<R | undefined>`
|
|
189
|
+
|
|
190
|
+
```javascript
|
|
191
|
+
const { data } = useApiRef('/api/users')
|
|
192
|
+
|
|
193
|
+
console.log(data.value) // undefined до загрузки
|
|
194
|
+
// После загрузки: массив пользователей
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
### `loading`
|
|
198
|
+
|
|
199
|
+
Ref с состоянием загрузки. `true` во время выполнения запроса.
|
|
200
|
+
|
|
201
|
+
**Тип:** `Ref<boolean>`
|
|
202
|
+
|
|
203
|
+
```javascript
|
|
204
|
+
const { loading } = useApiRef('/api/users')
|
|
205
|
+
|
|
206
|
+
console.log(loading.value) // true во время загрузки, false после
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
### `isStarting`
|
|
210
|
+
|
|
211
|
+
Computed, показывает, загружены ли данные хотя бы раз. `true` до первой загрузки.
|
|
212
|
+
|
|
213
|
+
**Тип:** `ComputedRef<boolean>`
|
|
214
|
+
|
|
215
|
+
```javascript
|
|
216
|
+
const { data, isStarting } = useApiRef('/api/users')
|
|
217
|
+
|
|
218
|
+
console.log(isStarting.value) // true до первой загрузки
|
|
219
|
+
// После первой загрузки всегда false, даже при повторных запросах
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
### `reading`
|
|
223
|
+
|
|
224
|
+
Computed, показывает активное чтение данных.
|
|
225
|
+
|
|
226
|
+
**Тип:** `ComputedRef<boolean>`
|
|
227
|
+
|
|
228
|
+
```javascript
|
|
229
|
+
const { reading } = useApiRef('/api/users')
|
|
230
|
+
|
|
231
|
+
console.log(reading.value) // true во время чтения данных
|
|
232
|
+
```
|
|
233
|
+
|
|
234
|
+
### `reset`
|
|
235
|
+
|
|
236
|
+
Функция для принудительного выполнения запроса.
|
|
237
|
+
|
|
238
|
+
**Тип:** `() => Promise<void>`
|
|
239
|
+
|
|
240
|
+
```javascript
|
|
241
|
+
const { data, reset } = useApiRef('/api/users')
|
|
242
|
+
|
|
243
|
+
// Принудительно перезагрузить данные
|
|
244
|
+
await reset()
|
|
245
|
+
```
|
|
246
|
+
|
|
247
|
+
## Примеры использования
|
|
248
|
+
|
|
249
|
+
### Список с фильтрами
|
|
250
|
+
|
|
251
|
+
```vue
|
|
252
|
+
<script setup>
|
|
253
|
+
import { ref, computed } from 'vue'
|
|
254
|
+
import { useApiRef } from '@dxtmisha/functional'
|
|
255
|
+
|
|
256
|
+
const searchQuery = ref('')
|
|
257
|
+
const currentPage = ref(1)
|
|
258
|
+
|
|
259
|
+
const { data: users, loading } = useApiRef(
|
|
260
|
+
'/api/users',
|
|
261
|
+
computed(() => ({
|
|
262
|
+
method: 'GET',
|
|
263
|
+
request: {
|
|
264
|
+
search: searchQuery.value,
|
|
265
|
+
page: currentPage.value,
|
|
266
|
+
limit: 20
|
|
267
|
+
}
|
|
268
|
+
}))
|
|
269
|
+
)
|
|
270
|
+
|
|
271
|
+
const handleSearch = (query) => {
|
|
272
|
+
searchQuery.value = query
|
|
273
|
+
currentPage.value = 1 // Сброс на первую страницу
|
|
274
|
+
// Запрос выполнится автоматически
|
|
275
|
+
}
|
|
276
|
+
</script>
|
|
277
|
+
|
|
278
|
+
<template>
|
|
279
|
+
<div>
|
|
280
|
+
<input v-model="searchQuery" placeholder="Поиск...">
|
|
281
|
+
<div v-if="loading">Загрузка...</div>
|
|
282
|
+
<div v-else>
|
|
283
|
+
<div v-for="user in users" :key="user.id">{{ user.name }}</div>
|
|
284
|
+
<button @click="currentPage++">Следующая страница</button>
|
|
285
|
+
</div>
|
|
286
|
+
</div>
|
|
287
|
+
</template>
|
|
288
|
+
```
|
|
289
|
+
|
|
290
|
+
### Условная загрузка
|
|
291
|
+
|
|
292
|
+
```vue
|
|
293
|
+
<script setup>
|
|
294
|
+
import { ref } from 'vue'
|
|
295
|
+
import { useApiRef } from '@dxtmisha/functional'
|
|
296
|
+
|
|
297
|
+
const showDetails = ref(false)
|
|
298
|
+
const userId = ref(1)
|
|
299
|
+
|
|
300
|
+
// Данные загружаются только когда showDetails === true
|
|
301
|
+
const { data: userDetails, loading } = useApiRef(
|
|
302
|
+
computed(() => `/api/users/${userId.value}/details`),
|
|
303
|
+
undefined,
|
|
304
|
+
true,
|
|
305
|
+
showDetails
|
|
306
|
+
)
|
|
307
|
+
|
|
308
|
+
const toggleDetails = () => {
|
|
309
|
+
showDetails.value = !showDetails.value
|
|
310
|
+
// Если showDetails стало true, запрос выполнится автоматически
|
|
311
|
+
}
|
|
312
|
+
</script>
|
|
313
|
+
|
|
314
|
+
<template>
|
|
315
|
+
<button @click="toggleDetails">
|
|
316
|
+
{{ showDetails ? 'Скрыть' : 'Показать' }} детали
|
|
317
|
+
</button>
|
|
318
|
+
<div v-if="showDetails">
|
|
319
|
+
<div v-if="loading">Загрузка деталей...</div>
|
|
320
|
+
<div v-else-if="userDetails">{{ userDetails }}</div>
|
|
321
|
+
</div>
|
|
322
|
+
</template>
|
|
323
|
+
```
|
|
324
|
+
|
|
325
|
+
### POST запрос с трансформацией
|
|
326
|
+
|
|
327
|
+
```vue
|
|
328
|
+
<script setup>
|
|
329
|
+
import { ref } from 'vue'
|
|
330
|
+
import { useApiRef } from '@dxtmisha/functional'
|
|
331
|
+
|
|
332
|
+
const formData = ref({
|
|
333
|
+
firstName: '',
|
|
334
|
+
lastName: '',
|
|
335
|
+
email: ''
|
|
336
|
+
})
|
|
337
|
+
|
|
338
|
+
const { data: createdUser, loading, reset } = useApiRef(
|
|
339
|
+
'/api/users',
|
|
340
|
+
{
|
|
341
|
+
method: 'POST',
|
|
342
|
+
request: formData
|
|
343
|
+
},
|
|
344
|
+
false, // Отключаем автоматическое выполнение
|
|
345
|
+
undefined,
|
|
346
|
+
(response) => {
|
|
347
|
+
// Преобразуем ответ API
|
|
348
|
+
return {
|
|
349
|
+
id: response.id,
|
|
350
|
+
fullName: `${response.firstName} ${response.lastName}`,
|
|
351
|
+
email: response.email,
|
|
352
|
+
createdAt: new Date(response.created_at)
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
)
|
|
356
|
+
|
|
357
|
+
const handleSubmit = async () => {
|
|
358
|
+
await reset() // Выполняем запрос вручную
|
|
359
|
+
if (createdUser.value) {
|
|
360
|
+
console.log('Пользователь создан:', createdUser.value)
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
</script>
|
|
364
|
+
|
|
365
|
+
<template>
|
|
366
|
+
<form @submit.prevent="handleSubmit">
|
|
367
|
+
<input v-model="formData.firstName" placeholder="Имя">
|
|
368
|
+
<input v-model="formData.lastName" placeholder="Фамилия">
|
|
369
|
+
<input v-model="formData.email" placeholder="Email">
|
|
370
|
+
<button :disabled="loading">
|
|
371
|
+
{{ loading ? 'Отправка...' : 'Создать' }}
|
|
372
|
+
</button>
|
|
373
|
+
</form>
|
|
374
|
+
</template>
|
|
375
|
+
```
|
|
376
|
+
|
|
377
|
+
### Множественные запросы
|
|
378
|
+
|
|
379
|
+
```vue
|
|
380
|
+
<script setup>
|
|
381
|
+
import { useApiRef } from '@dxtmisha/functional'
|
|
382
|
+
|
|
383
|
+
const { data: users, loading: usersLoading } = useApiRef('/api/users')
|
|
384
|
+
const { data: posts, loading: postsLoading } = useApiRef('/api/posts')
|
|
385
|
+
const { data: comments, loading: commentsLoading } = useApiRef('/api/comments')
|
|
386
|
+
|
|
387
|
+
const isLoading = computed(() =>
|
|
388
|
+
usersLoading.value || postsLoading.value || commentsLoading.value
|
|
389
|
+
)
|
|
390
|
+
</script>
|
|
391
|
+
|
|
392
|
+
<template>
|
|
393
|
+
<div v-if="isLoading">Загрузка данных...</div>
|
|
394
|
+
<div v-else>
|
|
395
|
+
<section>
|
|
396
|
+
<h2>Пользователи</h2>
|
|
397
|
+
<div v-for="user in users" :key="user.id">{{ user.name }}</div>
|
|
398
|
+
</section>
|
|
399
|
+
<section>
|
|
400
|
+
<h2>Посты</h2>
|
|
401
|
+
<div v-for="post in posts" :key="post.id">{{ post.title }}</div>
|
|
402
|
+
</section>
|
|
403
|
+
<section>
|
|
404
|
+
<h2>Комментарии</h2>
|
|
405
|
+
<div v-for="comment in comments" :key="comment.id">{{ comment.text }}</div>
|
|
406
|
+
</section>
|
|
407
|
+
</div>
|
|
408
|
+
</template>
|
|
409
|
+
```
|
|
410
|
+
|
|
411
|
+
## Глобальные условия
|
|
412
|
+
|
|
413
|
+
Функция `setApiRefGlobalConditions` позволяет установить глобальное условие для всех useApiRef.
|
|
414
|
+
|
|
415
|
+
```javascript
|
|
416
|
+
import { setApiRefGlobalConditions, useApiRef } from '@dxtmisha/functional'
|
|
417
|
+
import { ref } from 'vue'
|
|
418
|
+
|
|
419
|
+
// Глобальное условие - например, статус авторизации
|
|
420
|
+
const isAuthenticated = ref(false)
|
|
421
|
+
setApiRefGlobalConditions(isAuthenticated)
|
|
422
|
+
|
|
423
|
+
// Теперь все useApiRef будут учитывать это условие
|
|
424
|
+
const { data: profile } = useApiRef('/api/profile')
|
|
425
|
+
const { data: settings } = useApiRef('/api/settings')
|
|
426
|
+
|
|
427
|
+
// Запросы не выполнятся, пока isAuthenticated === false
|
|
428
|
+
isAuthenticated.value = true // Все запросы выполнятся автоматически
|
|
429
|
+
```
|
|
430
|
+
|
|
431
|
+
## Интеграция с Api классом
|
|
432
|
+
|
|
433
|
+
useApiRef использует класс Api, поэтому все настройки Api применяются автоматически:
|
|
434
|
+
|
|
435
|
+
```javascript
|
|
436
|
+
import { Api, useApiRef } from '@dxtmisha/functional'
|
|
437
|
+
|
|
438
|
+
// Настройка базового URL и заголовков
|
|
439
|
+
Api.setUrl('/api/v1/')
|
|
440
|
+
Api.setHeaders({
|
|
441
|
+
'Authorization': 'Bearer token123',
|
|
442
|
+
'Accept': 'application/json'
|
|
443
|
+
})
|
|
444
|
+
|
|
445
|
+
// useApiRef автоматически использует эти настройки
|
|
446
|
+
const { data } = useApiRef('/users') // Запрос к /api/v1/users с заголовками
|
|
447
|
+
```
|
|
448
|
+
|
|
449
|
+
## TypeScript
|
|
450
|
+
|
|
451
|
+
```typescript
|
|
452
|
+
interface User {
|
|
453
|
+
id: number
|
|
454
|
+
name: string
|
|
455
|
+
email: string
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
interface ApiResponse<T> {
|
|
459
|
+
data: T[]
|
|
460
|
+
total: number
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
// Типизация данных ответа
|
|
464
|
+
const { data } = useApiRef<User[]>('/api/users')
|
|
465
|
+
|
|
466
|
+
// Типизация с трансформацией
|
|
467
|
+
const { data } = useApiRef<User[], ApiResponse<User>>(
|
|
468
|
+
'/api/users',
|
|
469
|
+
undefined,
|
|
470
|
+
true,
|
|
471
|
+
undefined,
|
|
472
|
+
(response) => response.data // response типизирован как ApiResponse<User>
|
|
473
|
+
)
|
|
474
|
+
```
|
|
475
|
+
|
|
476
|
+
## Особенности поведения
|
|
477
|
+
|
|
478
|
+
### Ленивая инициализация
|
|
479
|
+
|
|
480
|
+
Запрос не выполняется до первого обращения к `data`:
|
|
481
|
+
|
|
482
|
+
```javascript
|
|
483
|
+
const api = useApiRef('/api/users')
|
|
484
|
+
|
|
485
|
+
// Запрос еще не выполнен
|
|
486
|
+
console.log('Композабл создан')
|
|
487
|
+
|
|
488
|
+
// Запрос выполнится при первом обращении к data
|
|
489
|
+
console.log(api.data.value)
|
|
490
|
+
```
|
|
491
|
+
|
|
492
|
+
### Автоматическая реактивность
|
|
493
|
+
|
|
494
|
+
При использовании ref или computed в параметрах, запросы выполняются автоматически:
|
|
495
|
+
|
|
496
|
+
```javascript
|
|
497
|
+
const userId = ref(1)
|
|
498
|
+
const { data } = useApiRef(computed(() => `/api/users/${userId.value}`))
|
|
499
|
+
|
|
500
|
+
// Каждое изменение userId вызывает новый запрос
|
|
501
|
+
userId.value = 2 // Запрос к /api/users/2
|
|
502
|
+
userId.value = 3 // Запрос к /api/users/3
|
|
503
|
+
```
|
|
504
|
+
|
|
505
|
+
### Предотвращение дублирования
|
|
506
|
+
|
|
507
|
+
Если запрос уже выполняется, новый запрос не начнётся:
|
|
508
|
+
|
|
509
|
+
```javascript
|
|
510
|
+
const { reset, loading } = useApiRef('/api/users')
|
|
511
|
+
|
|
512
|
+
await reset() // Первый запрос
|
|
513
|
+
// loading.value === true
|
|
514
|
+
|
|
515
|
+
await reset() // Этот вызов будет проигнорирован, пока первый не завершится
|
|
516
|
+
```
|
|
517
|
+
|