Skip to content

Commit 1954122

Browse files
authored
Merge pull request #135 from danybeltran/feat-imperative-httpreact
feat(HttpReact):
2 parents 5361193 + 793e7c8 commit 1954122

File tree

9 files changed

+285
-227
lines changed

9 files changed

+285
-227
lines changed

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "http-react",
3-
"version": "2.6.6",
3+
"version": "2.6.7",
44
"description": "React hooks for data fetching",
55
"main": "dist/index.js",
66
"scripts": {

src/components/index.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
'use client'
12
import * as React from 'react'
23
import { useEffect, useState, Suspense } from 'react'
34

@@ -12,7 +13,7 @@ import {
1213

1314
import { FetchContextType } from '../types'
1415

15-
import { isDefined, serialize } from '../utils'
16+
import { isDefined, serialize } from '../utils/shared'
1617

1718
/**
1819
* This is a wrapper around `Suspense`. It will render `fallback` during the first render and then leave the rendering to `Suspense`. If you are not using SSR, you should continue using the `Suspense` component.

src/hooks/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
'use client'
12
export { useFetch } from './use-fetch'
23

34
export {

src/hooks/others.ts

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
'use client'
12
import * as React from 'react'
23
import { useEffect } from 'react'
34

@@ -23,12 +24,9 @@ import {
2324

2425
import { useFetch } from './use-fetch'
2526

26-
import {
27-
createImperativeFetch,
28-
isDefined,
29-
isFunction,
30-
serialize
31-
} from '../utils'
27+
import { createImperativeFetch } from '../utils'
28+
29+
import { isDefined, isFunction, serialize } from '../utils/shared'
3230

3331
import {
3432
ALLOWED_CONTEXT_KEYS,

src/hooks/use-fetch.ts

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
'use client'
12
import * as React from 'react'
23
import { useState, useEffect } from 'react'
34

@@ -42,19 +43,21 @@ import {
4243

4344
import {
4445
createImperativeFetch,
45-
createRequestFn,
4646
getMiliseconds,
4747
getTimePassed,
48+
revalidate
49+
} from '../utils'
50+
import {
51+
createRequestFn,
4852
hasBaseUrl,
4953
isDefined,
5054
isFunction,
5155
notNull,
5256
queue,
53-
revalidate,
5457
serialize,
5558
setURLParams,
5659
windowExists
57-
} from '../utils'
60+
} from '../utils/shared'
5861

5962
/**
6063
* Fetch hook
@@ -1248,3 +1251,5 @@ useFetch.patch = createRequestFn('PATCH', '', {})
12481251
useFetch.purge = createRequestFn('PURGE', '', {})
12491252
useFetch.link = createRequestFn('LINK', '', {})
12501253
useFetch.unlink = createRequestFn('UNLINK', '', {})
1254+
1255+
useFetch.extend = createImperativeFetch

src/index.ts

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
'use client'
21
/**
32
* @license http-react
43
* Copyright (c) Dany Beltran
@@ -42,13 +41,17 @@ export {
4241

4342
export { FetchConfig, SSRSuspense } from './components'
4443

45-
export {
46-
gql,
47-
setURLParams,
48-
queryProvider,
49-
mutateData,
50-
revalidate,
51-
hasBaseUrl
52-
} from './utils'
44+
export { gql, queryProvider, mutateData, revalidate } from './utils'
5345

5446
export { defaultCache } from './internal'
47+
48+
export {
49+
HttpReact,
50+
setURLParams,
51+
hasBaseUrl,
52+
isDefined,
53+
isFormData,
54+
isFunction,
55+
serialize,
56+
notNull
57+
} from './utils/shared'

src/internal/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
'use client'
12
import { createContext, useContext } from 'react'
23

34
import { CacheStoreType, FetchContextType } from '../types'

src/utils/index.ts

Lines changed: 3 additions & 207 deletions
Original file line numberDiff line numberDiff line change
@@ -1,33 +1,27 @@
1+
'use client'
12
import * as React from 'react'
23
import { useGql } from '../hooks/others'
34
import { useFetch } from '../hooks/use-fetch'
45

56
import {
67
cacheForMutation,
7-
defaultCache,
88
previousConfig,
99
requestInitialTimes,
1010
requestsProvider,
1111
runningMutate,
1212
valuesMemory
1313
} from '../internal'
1414

15-
import {
16-
DEFAULT_RESOLVER,
17-
METHODS,
18-
UNITS_MILISECONDS_EQUIVALENTS
19-
} from '../internal/constants'
15+
import { UNITS_MILISECONDS_EQUIVALENTS } from '../internal/constants'
2016

2117
import {
2218
CacheStoreType,
2319
FetchContextType,
2420
ImperativeFetch,
25-
RequestWithBody,
2621
FetchInit,
2722
TimeSpan
2823
} from '../types'
29-
30-
export const windowExists = typeof window !== 'undefined'
24+
import { hasBaseUrl, isDefined, isFunction, queue, serialize } from './shared'
3125

3226
export function getMiliseconds(v: TimeSpan): number {
3327
if (typeof v === 'number') return v
@@ -43,207 +37,13 @@ export function getMiliseconds(v: TimeSpan): number {
4337
return amountNumber * UNITS_MILISECONDS_EQUIVALENTS[unit]
4438
}
4539

46-
export function notNull(target: any) {
47-
return target !== null
48-
}
49-
50-
export function isDefined(target: any) {
51-
return typeof target !== 'undefined'
52-
}
53-
54-
export function isFunction(target: any) {
55-
return typeof target === 'function'
56-
}
57-
58-
export function hasBaseUrl(target: string) {
59-
return target.startsWith('http://') || target.startsWith('https://')
60-
}
61-
62-
export function jsonCompare(a: any, b: any) {
63-
return JSON.stringify(a) === JSON.stringify(b)
64-
}
65-
66-
export function serialize(input: any) {
67-
return JSON.stringify(input)
68-
}
69-
70-
export const isFormData = (target: any) => {
71-
if (typeof FormData !== 'undefined') {
72-
return target instanceof FormData
73-
} else return false
74-
}
75-
76-
export function queue(callback: any, time: number = 0) {
77-
const tm = setTimeout(() => {
78-
callback()
79-
clearTimeout(tm)
80-
}, time)
81-
82-
return tm
83-
}
84-
85-
/**
86-
*
87-
* @param str The target string
88-
* @param $params The params to parse in the url
89-
*
90-
* Params should be separated by `"/"`, (e.g. `"/api/[resource]/:id"`)
91-
*
92-
* URL search params will not be affected
93-
*/
94-
export function setURLParams(str: string = '', $params: any = {}) {
95-
const hasQuery = str.includes('?')
96-
97-
const queryString =
98-
'?' +
99-
str
100-
.split('?')
101-
.filter((_, i) => i > 0)
102-
.join('?')
103-
104-
return (
105-
str
106-
.split('/')
107-
.map($segment => {
108-
const [segment] = $segment.split('?')
109-
if (segment.startsWith('[') && segment.endsWith(']')) {
110-
const paramName = segment.replace(/\[|\]/g, '')
111-
if (!(paramName in $params)) {
112-
console.warn(
113-
`Param '${paramName}' does not exist in params configuration for '${str}'`
114-
)
115-
return paramName
116-
}
117-
118-
return $params[segment.replace(/\[|\]/g, '')]
119-
} else if (segment.startsWith(':')) {
120-
const paramName = segment.split('').slice(1).join('')
121-
if (!(paramName in $params)) {
122-
console.warn(
123-
`Param '${paramName}' does not exist in params configuration for '${str}'`
124-
)
125-
return paramName
126-
}
127-
return $params[paramName]
128-
} else {
129-
return segment
130-
}
131-
})
132-
.join('/') + (hasQuery ? queryString : '')
133-
)
134-
}
135-
13640
export function getTimePassed(key: any) {
13741
return (
13842
Date.now() -
13943
(isDefined(requestInitialTimes[key]) ? requestInitialTimes[key] : 0)
14044
)
14145
}
14246

143-
/**
144-
* Creates a new request function. This is for usage with fetcher and fetcher.extend
145-
*/
146-
export function createRequestFn(
147-
method: string,
148-
baseUrl: string,
149-
$headers: any
150-
): RequestWithBody {
151-
return async function (url, init = {}) {
152-
const {
153-
default: def,
154-
params = {},
155-
headers,
156-
query = {},
157-
body,
158-
formatBody,
159-
resolver = DEFAULT_RESOLVER,
160-
onResolve = () => {},
161-
onError = () => {}
162-
} = init
163-
164-
const rawUrl = setURLParams(url, params)
165-
166-
const reqQueryString = Object.keys(query)
167-
.map(q => [q, query[q]].join('='))
168-
.join('&')
169-
170-
const reqConfig = {
171-
method,
172-
headers: {
173-
'Content-Type': 'application/json',
174-
...$headers,
175-
...headers
176-
},
177-
body: canHaveBody(method as any)
178-
? isFunction(formatBody)
179-
? (formatBody as any)(body)
180-
: body
181-
: undefined
182-
}
183-
184-
let r = undefined as any
185-
186-
const requestUrl = [
187-
baseUrl || '',
188-
rawUrl,
189-
url.includes('?') ? '&' : '?',
190-
reqQueryString
191-
].join('')
192-
193-
try {
194-
const req = await fetch(requestUrl, {
195-
...init,
196-
...reqConfig
197-
})
198-
r = req
199-
200-
const data = await resolver(req)
201-
if (req?.status >= 400) {
202-
onError(true as any)
203-
return {
204-
res: req,
205-
data: def,
206-
error: true,
207-
code: req?.status,
208-
config: {
209-
...init,
210-
url: `${baseUrl || ''}${rawUrl}`,
211-
...reqConfig,
212-
query
213-
}
214-
}
215-
} else {
216-
onResolve(data, req)
217-
return {
218-
res: req,
219-
data: data,
220-
error: false,
221-
code: req?.status,
222-
config: {
223-
...init,
224-
url: `${baseUrl || ''}${rawUrl}`,
225-
...reqConfig,
226-
query
227-
}
228-
}
229-
}
230-
} catch (err) {
231-
onError(err as any)
232-
return {
233-
res: r,
234-
data: def,
235-
error: true,
236-
code: r?.status,
237-
config: {
238-
...init,
239-
url: requestUrl,
240-
...reqConfig
241-
}
242-
}
243-
}
244-
} as RequestWithBody
245-
}
246-
24747
export const createImperativeFetch = (ctx: FetchContextType) => {
24848
const keys = [
24949
'GET',
@@ -498,7 +298,3 @@ export function mutateData(
498298
} catch (err) {}
499299
}
500300
}
501-
502-
export function canHaveBody(method: keyof typeof METHODS) {
503-
return /(POST|PUT|DELETE|PATCH)/.test(method)
504-
}

0 commit comments

Comments
 (0)