Press n or j to go to the next uncovered block, b, p or k for the previous block.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 | 3x 3x 3x 3x 3x 3x 30x 30x 30x 27x 27x 27x 27x 27x 27x 27x 16x 10x 10x 10x 10x 10x 10x 9x 9x 1x 1x 1x 1x 10x 27x 27x 5x 81x 27x 3x | import { FpjsContextInterface, FpjsContext, GetDataOptions, QueryResult, VisitorQueryContext } from './fpjs-context' import { useCallback, useContext, useEffect, useState } from 'react' import { GetOptions, VisitorData } from '@fingerprintjs/fingerprintjs-pro-spa' import { usePrevious } from './utils/use-previous' import deepEquals from 'fast-deep-equal' import { toError } from './utils/to-error' import { assertIsTruthy } from './utils/assert-is-truthy' export type UseVisitorDataOptions<TExtended extends boolean> = GetDataOptions<TExtended> /** * @example * ```js * const { * // Request state * data, * isLoading, * error, * // A method to be called manually when the `immediate` field in the config is set to `false`: * getData, * } = useVisitorData({ extended: true }, { immediate: false }); * ``` * Use the `useVisitorData` hook in your components to perform identification requests with the FingerprintJS API. The returned object contains information about loading status, errors, and visitor. * * @param getOptions options for the `fp.get()` request * @param config config for the hook */ export function useVisitorData<TExtended extends boolean>( getOptions: UseVisitorDataOptions<TExtended> = {}, config: UseVisitorDataConfig = defaultUseVisitorDataConfig ): VisitorQueryContext<TExtended> { assertIsTruthy(getOptions, 'getOptions') const previousGetOptions = usePrevious(getOptions) const { immediate } = config const { getVisitorData } = useContext<FpjsContextInterface<TExtended>>(FpjsContext) const initialState = { isLoading: config.immediate ? true : false } const [state, setState] = useState<QueryResult<VisitorData<TExtended>>>(initialState) const getData = useCallback<VisitorQueryContext<TExtended>['getData']>( async (params = {}) => { assertIsTruthy(params, 'getDataParams') const { ignoreCache, ...getDataPassedOptions } = params try { setState((state) => ({ ...state, isLoading: true })) const { ignoreCache: defaultIgnoreCache, ...getVisitorDataOptions } = getOptions const getDataOptions: GetOptions<TExtended> = { ...getVisitorDataOptions, ...getDataPassedOptions } const result = await getVisitorData( getDataOptions, typeof ignoreCache === 'boolean' ? ignoreCache : defaultIgnoreCache ) setState((state) => ({ ...state, data: result, isLoading: false, error: undefined })) return result } catch (unknownError) { const error = toError(unknownError) error.name = 'FPJSAgentError' setState((state) => ({ ...state, data: undefined, error })) throw error } finally { setState((state) => (state.isLoading ? { ...state, isLoading: false } : state)) } }, [getOptions, getVisitorData] ) useEffect(() => { if (immediate && (!previousGetOptions || !deepEquals(getOptions, previousGetOptions))) { getData().catch((error) => { console.error(`Failed to fetch visitor data on mount: ${error}`) }) } }, [immediate, getData, previousGetOptions, getOptions]) const { isLoading, data, error } = state return { getData, isLoading, data, error, } } export interface UseVisitorDataConfig { /** * Determines whether the `getData()` method will be called immediately after the hook mounts or not */ immediate: boolean } const defaultUseVisitorDataConfig = { immediate: true } |