Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "http-react",
"version": "2.6.6",
"version": "2.6.7",
"description": "React hooks for data fetching",
"main": "dist/index.js",
"scripts": {
Expand Down
3 changes: 2 additions & 1 deletion src/components/index.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
'use client'
import * as React from 'react'
import { useEffect, useState, Suspense } from 'react'

Expand All @@ -12,7 +13,7 @@ import {

import { FetchContextType } from '../types'

import { isDefined, serialize } from '../utils'
import { isDefined, serialize } from '../utils/shared'

/**
* 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.
Expand Down
1 change: 1 addition & 0 deletions src/hooks/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
'use client'
export { useFetch } from './use-fetch'

export {
Expand Down
10 changes: 4 additions & 6 deletions src/hooks/others.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
'use client'
import * as React from 'react'
import { useEffect } from 'react'

Expand All @@ -23,12 +24,9 @@ import {

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

import {
createImperativeFetch,
isDefined,
isFunction,
serialize
} from '../utils'
import { createImperativeFetch } from '../utils'

import { isDefined, isFunction, serialize } from '../utils/shared'

import {
ALLOWED_CONTEXT_KEYS,
Expand Down
11 changes: 8 additions & 3 deletions src/hooks/use-fetch.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
'use client'
import * as React from 'react'
import { useState, useEffect } from 'react'

Expand Down Expand Up @@ -42,19 +43,21 @@ import {

import {
createImperativeFetch,
createRequestFn,
getMiliseconds,
getTimePassed,
revalidate
} from '../utils'
import {
createRequestFn,
hasBaseUrl,
isDefined,
isFunction,
notNull,
queue,
revalidate,
serialize,
setURLParams,
windowExists
} from '../utils'
} from '../utils/shared'

/**
* Fetch hook
Expand Down Expand Up @@ -1248,3 +1251,5 @@ useFetch.patch = createRequestFn('PATCH', '', {})
useFetch.purge = createRequestFn('PURGE', '', {})
useFetch.link = createRequestFn('LINK', '', {})
useFetch.unlink = createRequestFn('UNLINK', '', {})

useFetch.extend = createImperativeFetch
21 changes: 12 additions & 9 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
'use client'
/**
* @license http-react
* Copyright (c) Dany Beltran
Expand Down Expand Up @@ -42,13 +41,17 @@ export {

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

export {
gql,
setURLParams,
queryProvider,
mutateData,
revalidate,
hasBaseUrl
} from './utils'
export { gql, queryProvider, mutateData, revalidate } from './utils'

export { defaultCache } from './internal'

export {
HttpReact,
setURLParams,
hasBaseUrl,
isDefined,
isFormData,
isFunction,
serialize,
notNull
} from './utils/shared'
1 change: 1 addition & 0 deletions src/internal/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
'use client'
import { createContext, useContext } from 'react'

import { CacheStoreType, FetchContextType } from '../types'
Expand Down
210 changes: 3 additions & 207 deletions src/utils/index.ts
Original file line number Diff line number Diff line change
@@ -1,33 +1,27 @@
'use client'
import * as React from 'react'
import { useGql } from '../hooks/others'
import { useFetch } from '../hooks/use-fetch'

import {
cacheForMutation,
defaultCache,
previousConfig,
requestInitialTimes,
requestsProvider,
runningMutate,
valuesMemory
} from '../internal'

import {
DEFAULT_RESOLVER,
METHODS,
UNITS_MILISECONDS_EQUIVALENTS
} from '../internal/constants'
import { UNITS_MILISECONDS_EQUIVALENTS } from '../internal/constants'

import {
CacheStoreType,
FetchContextType,
ImperativeFetch,
RequestWithBody,
FetchInit,
TimeSpan
} from '../types'

export const windowExists = typeof window !== 'undefined'
import { hasBaseUrl, isDefined, isFunction, queue, serialize } from './shared'

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

export function notNull(target: any) {
return target !== null
}

export function isDefined(target: any) {
return typeof target !== 'undefined'
}

export function isFunction(target: any) {
return typeof target === 'function'
}

export function hasBaseUrl(target: string) {
return target.startsWith('http://') || target.startsWith('https://')
}

export function jsonCompare(a: any, b: any) {
return JSON.stringify(a) === JSON.stringify(b)
}

export function serialize(input: any) {
return JSON.stringify(input)
}

export const isFormData = (target: any) => {
if (typeof FormData !== 'undefined') {
return target instanceof FormData
} else return false
}

export function queue(callback: any, time: number = 0) {
const tm = setTimeout(() => {
callback()
clearTimeout(tm)
}, time)

return tm
}

/**
*
* @param str The target string
* @param $params The params to parse in the url
*
* Params should be separated by `"/"`, (e.g. `"/api/[resource]/:id"`)
*
* URL search params will not be affected
*/
export function setURLParams(str: string = '', $params: any = {}) {
const hasQuery = str.includes('?')

const queryString =
'?' +
str
.split('?')
.filter((_, i) => i > 0)
.join('?')

return (
str
.split('/')
.map($segment => {
const [segment] = $segment.split('?')
if (segment.startsWith('[') && segment.endsWith(']')) {
const paramName = segment.replace(/\[|\]/g, '')
if (!(paramName in $params)) {
console.warn(
`Param '${paramName}' does not exist in params configuration for '${str}'`
)
return paramName
}

return $params[segment.replace(/\[|\]/g, '')]
} else if (segment.startsWith(':')) {
const paramName = segment.split('').slice(1).join('')
if (!(paramName in $params)) {
console.warn(
`Param '${paramName}' does not exist in params configuration for '${str}'`
)
return paramName
}
return $params[paramName]
} else {
return segment
}
})
.join('/') + (hasQuery ? queryString : '')
)
}

export function getTimePassed(key: any) {
return (
Date.now() -
(isDefined(requestInitialTimes[key]) ? requestInitialTimes[key] : 0)
)
}

/**
* Creates a new request function. This is for usage with fetcher and fetcher.extend
*/
export function createRequestFn(
method: string,
baseUrl: string,
$headers: any
): RequestWithBody {
return async function (url, init = {}) {
const {
default: def,
params = {},
headers,
query = {},
body,
formatBody,
resolver = DEFAULT_RESOLVER,
onResolve = () => {},
onError = () => {}
} = init

const rawUrl = setURLParams(url, params)

const reqQueryString = Object.keys(query)
.map(q => [q, query[q]].join('='))
.join('&')

const reqConfig = {
method,
headers: {
'Content-Type': 'application/json',
...$headers,
...headers
},
body: canHaveBody(method as any)
? isFunction(formatBody)
? (formatBody as any)(body)
: body
: undefined
}

let r = undefined as any

const requestUrl = [
baseUrl || '',
rawUrl,
url.includes('?') ? '&' : '?',
reqQueryString
].join('')

try {
const req = await fetch(requestUrl, {
...init,
...reqConfig
})
r = req

const data = await resolver(req)
if (req?.status >= 400) {
onError(true as any)
return {
res: req,
data: def,
error: true,
code: req?.status,
config: {
...init,
url: `${baseUrl || ''}${rawUrl}`,
...reqConfig,
query
}
}
} else {
onResolve(data, req)
return {
res: req,
data: data,
error: false,
code: req?.status,
config: {
...init,
url: `${baseUrl || ''}${rawUrl}`,
...reqConfig,
query
}
}
}
} catch (err) {
onError(err as any)
return {
res: r,
data: def,
error: true,
code: r?.status,
config: {
...init,
url: requestUrl,
...reqConfig
}
}
}
} as RequestWithBody
}

export const createImperativeFetch = (ctx: FetchContextType) => {
const keys = [
'GET',
Expand Down Expand Up @@ -498,7 +298,3 @@ export function mutateData(
} catch (err) {}
}
}

export function canHaveBody(method: keyof typeof METHODS) {
return /(POST|PUT|DELETE|PATCH)/.test(method)
}
Loading