4
0
forked from crowetic/commerce

Updated how the hook input is handled

This commit is contained in:
Luis Alvarez 2021-02-09 13:23:48 -05:00
parent 016be86d9a
commit 5aecb0f303
8 changed files with 45 additions and 28 deletions

View File

@ -1,4 +1,4 @@
import { ReactNode } from 'react' import type { ReactNode } from 'react'
import { import {
CommerceConfig, CommerceConfig,
CommerceProvider as CoreCommerceProvider, CommerceProvider as CoreCommerceProvider,

View File

@ -43,7 +43,7 @@ const fetcher: Fetcher = async ({
const useCart: HookHandler< const useCart: HookHandler<
Cart | null, Cart | null,
[], {},
FetchCartInput, FetchCartInput,
any, any,
any, any,
@ -71,7 +71,7 @@ const useCart: HookHandler<
const useWishlist: HookHandler< const useWishlist: HookHandler<
Cart | null, Cart | null,
[], {},
FetchCartInput, FetchCartInput,
any, any,
any, any,

View File

@ -1,8 +1,8 @@
import { useMemo } from 'react' import { useMemo } from 'react'
import Cookies from 'js-cookie' import Cookies from 'js-cookie'
import type { Cart } from '../types'
import type { HookFetcherFn } from '../utils/types' import type { HookFetcherFn } from '../utils/types'
import useData from '../utils/use-data-2' import useData from '../utils/use-data-2'
import type { Cart } from '../types'
import { Provider, useCommerce } from '..' import { Provider, useCommerce } from '..'
export type FetchCartInput = { export type FetchCartInput = {
@ -13,13 +13,17 @@ export type CartResponse<P extends Provider> = ReturnType<
NonNullable<NonNullable<NonNullable<P['cart']>['useCart']>['onResponse']> NonNullable<NonNullable<NonNullable<P['cart']>['useCart']>['onResponse']>
> >
export type UseCart<P extends Provider> = ( export type UseCartInput<P extends Provider> = Parameters<
...input: UseCartInput<P> NonNullable<
) => CartResponse<P>
export type UseCartInput<P extends Provider> = NonNullable<
NonNullable<NonNullable<NonNullable<P['cart']>['useCart']>>['input'] NonNullable<NonNullable<NonNullable<P['cart']>['useCart']>>['input']
> >
>[0]
export type UseCart<P extends Provider> = Partial<
UseCartInput<P>
> extends UseCartInput<P>
? (input?: UseCartInput<P>) => CartResponse<P>
: (input: UseCartInput<P>) => CartResponse<P>
export const fetcher: HookFetcherFn<Cart | null, FetchCartInput> = async ({ export const fetcher: HookFetcherFn<Cart | null, FetchCartInput> = async ({
options, options,
@ -31,7 +35,7 @@ export const fetcher: HookFetcherFn<Cart | null, FetchCartInput> = async ({
return data && normalize ? normalize(data) : data return data && normalize ? normalize(data) : data
} }
export default function useCart<P extends Provider>(...input: UseCartInput<P>) { export default function useCart<P extends Provider>(input?: UseCartInput<P>) {
const { providerRef, fetcherRef, cartCookie } = useCommerce<P>() const { providerRef, fetcherRef, cartCookie } = useCommerce<P>()
const provider = providerRef.current const provider = providerRef.current
@ -43,7 +47,7 @@ export default function useCart<P extends Provider>(...input: UseCartInput<P>) {
} }
const response = useData( const response = useData(
{ ...opts, fetcher: wrapper }, { ...opts, fetcher: wrapper },
input, opts?.input ? opts.input(input ?? {}) : [],
provider.fetcher ?? fetcherRef.current provider.fetcher ?? fetcherRef.current
) )
const memoizedResponse = useMemo( const memoizedResponse = useMemo(

View File

@ -16,10 +16,10 @@ const Commerce = createContext<CommerceContextValue<any> | {}>({})
export type Provider = CommerceConfig & { export type Provider = CommerceConfig & {
fetcher: Fetcher fetcher: Fetcher
cart?: { cart?: {
useCart?: HookHandler<Cart | null, [...any], FetchCartInput> useCart?: HookHandler<Cart | null, {}, FetchCartInput>
} }
wishlist?: { wishlist?: {
useWishlist?: HookHandler<Cart | null, [...any], FetchCartInput> useWishlist?: HookHandler<Cart | null, {}, FetchCartInput>
} }
} }

View File

@ -4,11 +4,15 @@ import type { ResponseState } from './use-data'
export type Override<T, K> = Omit<T, keyof K> & K export type Override<T, K> = Omit<T, keyof K> & K
// Returns the properties in T with the properties in type K changed from optional to required /**
* Returns the properties in T with the properties in type K changed from optional to required
*/
export type PickRequired<T, K extends keyof T> = Omit<T, K> & export type PickRequired<T, K extends keyof T> = Omit<T, K> &
Required<Pick<T, K>> Required<Pick<T, K>>
// Core fetcher added by CommerceProvider /**
* Core fetcher added by CommerceProvider
*/
export type Fetcher<T = any, B = any> = ( export type Fetcher<T = any, B = any> = (
options: FetcherOptions<B> options: FetcherOptions<B>
) => T | Promise<T> ) => T | Promise<T>
@ -47,15 +51,17 @@ export type HookFetcherOptions = {
export type HookInputValue = string | number | boolean | undefined export type HookInputValue = string | number | boolean | undefined
export type HookInput = [string, HookInputValue][] export type HookSwrInput = [string, HookInputValue][]
export type HookFetchInput = { [k: string]: HookInputValue } export type HookFetchInput = { [k: string]: HookInputValue }
export type HookInput = {}
export type HookHandler< export type HookHandler<
// Data obj returned by the hook and fetch operation // Data obj returned by the hook and fetch operation
Data, Data,
// Input expected by the hook // Input expected by the hook
Input = [...any], Input extends { [k: string]: unknown } = {},
// Input expected before doing a fetch operation // Input expected before doing a fetch operation
FetchInput extends HookFetchInput = never, FetchInput extends HookFetchInput = never,
// Data returned by the API after a fetch operation // Data returned by the API after a fetch operation
@ -65,7 +71,9 @@ export type HookHandler<
// Custom state added to the response object of SWR // Custom state added to the response object of SWR
State = {} State = {}
> = { > = {
input?: Input input?(
input: Input & { swrOptions?: SwrOptions<Data, FetchInput, Result> }
): HookFetchInput | HookSwrInput
swrOptions?: SwrOptions<Data, FetchInput, Result> swrOptions?: SwrOptions<Data, FetchInput, Result>
onResponse?(response: ResponseState<Data>): ResponseState<Data> & State onResponse?(response: ResponseState<Data>): ResponseState<Data> & State
onMutation?: any onMutation?: any

View File

@ -1,7 +1,7 @@
import useSWR, { responseInterface } from 'swr' import useSWR, { responseInterface } from 'swr'
import type { import type {
HookHandler, HookHandler,
HookInput, HookSwrInput,
HookFetchInput, HookFetchInput,
PickRequired, PickRequired,
Fetcher, Fetcher,
@ -15,7 +15,7 @@ export type ResponseState<Result> = responseInterface<Result, CommerceError> & {
export type UseData = < export type UseData = <
Data = any, Data = any,
Input = [...any], Input extends { [k: string]: unknown } = {},
FetchInput extends HookFetchInput = never, FetchInput extends HookFetchInput = never,
Result = any, Result = any,
Body = any Body = any
@ -24,11 +24,12 @@ export type UseData = <
HookHandler<Data, Input, FetchInput, Result, Body>, HookHandler<Data, Input, FetchInput, Result, Body>,
'fetcher' 'fetcher'
>, >,
input: HookInput, input: HookFetchInput | HookSwrInput,
fetcherFn: Fetcher fetcherFn: Fetcher
) => ResponseState<Data> ) => ResponseState<Data>
const useData: UseData = (options, input, fetcherFn) => { const useData: UseData = (options, input, fetcherFn) => {
const hookInput = Array.isArray(input) ? input : Object.entries(input)
const fetcher = async ( const fetcher = async (
url?: string, url?: string,
query?: string, query?: string,
@ -40,7 +41,7 @@ const useData: UseData = (options, input, fetcherFn) => {
options: { url, query, method }, options: { url, query, method },
// Transform the input array into an object // Transform the input array into an object
input: args.reduce((obj, val, i) => { input: args.reduce((obj, val, i) => {
obj[input[i][0]!] = val obj[hookInput[i][0]!] = val
return obj return obj
}, {}), }, {}),
fetch: fetcherFn, fetch: fetcherFn,
@ -59,7 +60,7 @@ const useData: UseData = (options, input, fetcherFn) => {
() => { () => {
const opts = options.fetchOptions const opts = options.fetchOptions
return opts return opts
? [opts.url, opts.query, opts.method, ...input.map((e) => e[1])] ? [opts.url, opts.query, opts.method, ...hookInput.map((e) => e[1])]
: null : null
}, },
fetcher, fetcher,

View File

@ -1,5 +1,5 @@
import useSWR, { ConfigInterface, responseInterface } from 'swr' import useSWR, { ConfigInterface, responseInterface } from 'swr'
import type { HookInput, HookFetcher, HookFetcherOptions } from './types' import type { HookSwrInput, HookFetcher, HookFetcherOptions } from './types'
import defineProperty from './define-property' import defineProperty from './define-property'
import { CommerceError } from './errors' import { CommerceError } from './errors'
import { useCommerce } from '..' import { useCommerce } from '..'
@ -16,7 +16,7 @@ export type ResponseState<Result> = responseInterface<Result, CommerceError> & {
export type UseData = <Data = any, Input = null, Result = any>( export type UseData = <Data = any, Input = null, Result = any>(
options: HookFetcherOptions | (() => HookFetcherOptions | null), options: HookFetcherOptions | (() => HookFetcherOptions | null),
input: HookInput, input: HookSwrInput,
fetcherFn: HookFetcher<Data, Input, Result>, fetcherFn: HookFetcher<Data, Input, Result>,
swrOptions?: SwrOptions<Data, Input, Result> swrOptions?: SwrOptions<Data, Input, Result>
) => ResponseState<Data> ) => ResponseState<Data>

View File

@ -1,4 +1,8 @@
import type { HookInput, HookFetcher, HookFetcherOptions } from '../utils/types' import type {
HookSwrInput,
HookFetcher,
HookFetcherOptions,
} from '../utils/types'
import useData, { ResponseState, SwrOptions } from '../utils/use-data' import useData, { ResponseState, SwrOptions } from '../utils/use-data'
export type WishlistResponse<Result> = ResponseState<Result> & { export type WishlistResponse<Result> = ResponseState<Result> & {
@ -7,7 +11,7 @@ export type WishlistResponse<Result> = ResponseState<Result> & {
export default function useWishlist<Result, Input = null>( export default function useWishlist<Result, Input = null>(
options: HookFetcherOptions, options: HookFetcherOptions,
input: HookInput, input: HookSwrInput,
fetcherFn: HookFetcher<Result, Input>, fetcherFn: HookFetcher<Result, Input>,
swrOptions?: SwrOptions<Result, Input> swrOptions?: SwrOptions<Result, Input>
): WishlistResponse<Result> { ): WishlistResponse<Result> {