diff --git a/README.md b/README.md index f1caeb6..2a72e2d 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ ### HTTP React -React hooks for data fetching +React hooks for data fetching, built on top of the native `Fetch` API.

@@ -8,7 +8,37 @@ React hooks for data fetching

-Installation: +#### Overview + +With one hook call, you get all the information about a request, and you can start making UIs that are more consistent and performant: + +```jsx +import useFetch from 'http-react' + +export default function App() { + const { data, loading, error } = useFetch('/api/user-info') + + if (loading) return

Loading

+ + if (error) return

An error ocurred

+ + return

Welcome, {data.name}

+} +``` + +It supports many features that are needed in data fetching in modern applications, while giving developers full control over the request configuration: + +- Server-Side Rendering +- React Native +- Request deduplication +- Suspense +- Refresh +- Retry on error +- qraphql + +and [more](https://http-react.netlify.app/docs/tutorial-basics/request-config)! + +#### Installation: ```bash npm install --save http-react @@ -20,5 +50,5 @@ Or yarn add http-react ``` -[Getting started](https://http-react.netlify.app) +[Getting started](https://http-react.netlify.app/docs/intro) diff --git a/package.json b/package.json index 69e0c7a..1f0ea1c 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "http-react", - "version": "2.5.9", + "version": "2.6.0", "description": "React hooks for data fetching", "main": "dist/index.js", "scripts": { diff --git a/src/hooks/use-fetch.ts b/src/hooks/use-fetch.ts index d4f59d6..262da08 100644 --- a/src/hooks/use-fetch.ts +++ b/src/hooks/use-fetch.ts @@ -82,7 +82,7 @@ export function useFetch( method = METHODS.GET as HTTP_METHODS, headers = {} as Headers, body = undefined as unknown as Body, - formatBody = (e) => JSON.stringify(e), + formatBody = e => JSON.stringify(e), resolver = isFunction(ctx.resolver) ? ctx.resolver : DEFAULT_RESOLVER, onError, @@ -132,15 +132,15 @@ export function useFetch( ? optionsConfig.retryOnReconnect : ctx.retryOnReconnect - const [reqQuery, setReqQuery] = useState({ + const reqQuery = { ...ctx.query, ...config.query - }) + } - const [reqParams, setReqParams] = useState({ + const reqParams = { ...ctx.params, ...config.params - }) + } const rawUrl = (hasBaseUrl(url) @@ -164,12 +164,6 @@ export function useFetch( const resolvedKey = serialize({ idString }) - const [configUrl, setConfigUrl] = useState(urls[resolvedKey]) - - useEffect(() => { - setConfigUrl(urls[resolvedKey]) - }, [serialize(urls[resolvedKey])]) - const suspense = $suspense || willSuspend[resolvedKey] if (suspense && !willSuspend[resolvedKey]) { @@ -188,17 +182,10 @@ export function useFetch( } } - useEffect(() => { - if (url !== '') { - setReqParams(() => { - const newParams = { - ...ctx.params, - ...config.params - } - return newParams - }) - } - }, [serialize({ ...ctx.params, ...config.params }), resolvedKey]) + const configUrl = urls[resolvedKey] || { + realUrl, + rawUrl + } const stringDeps = serialize( Object.assign( @@ -254,39 +241,6 @@ export function useFetch( } }, []) - useEffect(() => { - let queryParamsFromString: any = {} - try { - // getting query params from passed url - const queryParts = qp.split('&') - queryParts.forEach((q, i) => { - const [key, value] = q.split('=') - if (queryParamsFromString[key] !== value) { - queryParamsFromString[key] = `${value}` - } - }) - } finally { - if (url !== '') { - setReqQuery(() => { - const newQuery = { - ...ctx.query, - ...queryParamsFromString, - ...config.query - } - return newQuery - }) - } - } - }, [ - resolvedKey, - requestCallId, - serialize({ - qp, - ...ctx.query, - ...config.query - }) - ]) - const requestCache = cacheProvider.get(resolvedKey) const initialDataValue = isDefined(valuesMemory[resolvedKey]) @@ -304,13 +258,11 @@ export function useFetch( const [online, setOnline] = useState(true) - const [requestHeaders, setRequestHeades] = useState< - object | Headers | undefined - >({ ...ctx.headers, ...config.headers }) - - const [response, setResponse] = useState>() + const requestHeaders = { + ...ctx.headers, + ...config.headers + } - const [statusCode, setStatusCode] = useState() const [error, setError] = useState(hasErrors[resolvedKey]) const [loading, setLoading] = useState( revalidateOnMount @@ -320,21 +272,10 @@ export function useFetch( : previousConfig[resolvedKey] !== serialize(optionsConfig) ) const [completedAttempts, setCompletedAttempts] = useState(0) + const [requestAbortController, setRequestAbortController] = useState(new AbortController()) - const [reqMethod, setReqMethod] = useState(config.method) - - useEffect(() => { - if (url !== '') { - setReqMethod(config.method) - requestsProvider.emit(resolvedKey, { - requestCallId, - method: config.method - }) - } - }, [stringDeps, response, requestAbortController, requestCallId]) - useEffect(() => { if (url !== '') { if (error && !hasErrors[resolvedKey]) { @@ -385,7 +326,6 @@ export function useFetch( if (previousConfig[resolvedKey] !== serialize(optionsConfig)) { previousProps[resolvedKey] = optionsConfig queue(() => { - setReqMethod(config.method) if (url !== '') { const newUrls = { realUrl, @@ -394,10 +334,6 @@ export function useFetch( urls[resolvedKey] = newUrls - setConfigUrl({ - rawUrl, - realUrl - }) requestsProvider.emit(resolvedKey, { requestCallId, realUrl: resKey, @@ -513,7 +449,7 @@ export function useFetch( }) } else { if (_data.errors && isGqlRequest) { - setData((previous) => { + setData(previous => { const newData = { ...previous, variables: (optionsConfig as any)?.variables, @@ -728,54 +664,16 @@ export function useFetch( // onResolve($data, lastResponses[resolvedKey]) } } - if (isDefined(method)) { - queue(() => { - setReqMethod(method) - }) - } - if (isDefined(config?.query)) { - queue(() => { - setReqQuery(config.query) - }) - } - if (isDefined(rawUrl) && isDefined(realUrl)) { - queue(() => { - setConfigUrl({ - rawUrl, - realUrl - }) - }) - } - if (isDefined(config?.params)) { - queue(() => { - setReqParams(config?.params) - }) - } - if (isDefined(config?.headers)) { - queue(() => { - setRequestHeades(config?.headers) - }) - } if (isDefined(completedAttempts)) { queue(() => { setCompletedAttempts(completedAttempts) }) } - if (isDefined(code)) { - queue(() => { - setStatusCode(code) - }) - } if (isDefined(requestAbortController)) { queue(() => { setRequestAbortController(requestAbortController) }) } - if (isDefined(response)) { - queue(() => { - setResponse(response) - }) - } if (isDefined(loading)) { queue(() => { setLoading(loading) @@ -857,19 +755,12 @@ export function useFetch( loading: true, error: null }) - const reqQ = { - ...ctx.query, - ...config.query - } - const reqP = { - ...ctx.params, - ...config.params - } + fetchData({ - query: Object.keys(reqQ) - .map((q) => [q, reqQ[q]].join('=')) + query: Object.keys(reqQuery) + .map(q => [q, reqQuery[q]].join('=')) .join('&'), - params: reqP + params: reqParams }) } } @@ -964,14 +855,6 @@ export function useFetch( } }, [onOffline, reValidate, resolvedKey, retryOnReconnect]) - useEffect(() => { - const newHeaders = { - ...ctx.headers, - ...config.headers - } - setRequestHeades(newHeaders) - }, [serialize({ ...ctx.headers, ...config.headers }), resolvedKey]) - useEffect(() => { if (revalidateOnMount) { if (suspense) { @@ -992,7 +875,7 @@ export function useFetch( if (error) { if (completedAttempts < (attempts as number)) { reValidate() - setCompletedAttempts((previousAttempts) => { + setCompletedAttempts(previousAttempts => { let newAttemptsValue = previousAttempts + 1 requestsProvider.emit(resolvedKey, { @@ -1040,19 +923,11 @@ export function useFetch( if (isPending(resolvedKey)) { setLoading(true) } - const reqQ = { - ...ctx.query, - ...config.query - } - const reqP = { - ...ctx.params, - ...config.params - } fetchData({ - query: Object.keys(reqQ) - .map((q) => [q, reqQ[q]].join('=')) + query: Object.keys(reqQuery) + .map(q => [q, reqParams[q]].join('=')) .join('&'), - params: reqP + params: reqParams }) } // It means a url is not passed @@ -1160,7 +1035,6 @@ export function useFetch( ...config, ...optionsConfig, ...previousProps[resolvedKey], - method: reqMethod, params: { ...reqParams, ...previousProps[resolvedKey]?.params @@ -1263,14 +1137,7 @@ export function useFetch( } } } - }, [ - url, - auto, - cancelOnChange, - serialize(id), - serialize(optionsConfig), - resolvedKey - ]) + }, [serialize(optionsConfig)]) const resolvedData = React.useMemo(() => data, [rawJSON])