Object.defineProperty(exports, '__esModule', { value: true }); var core = require('@urql/core'); var React = require('react'); var wonka = require('wonka'); var OBJ = {}; /** `urql`'s React Context. * * @remarks * The React Context that `urql`’s {@link Client} will be provided with. * You may use the reexported {@link Provider} to provide a `Client` as well. */ var Context = React.createContext(OBJ); /** Provider for `urql`'s {@link Client} to GraphQL hooks. * * @remarks * `Provider` accepts a {@link Client} and provides it to all GraphQL hooks, * and {@link useClient}. * * You should make sure to create a {@link Client} and provide it with the * `Provider` to parts of your component tree that use GraphQL hooks. * * @example * ```tsx * import { Provider } from 'urql'; * // All of `@urql/core` is also re-exported by `urql`: * import { Client, cacheExchange, fetchExchange } from '@urql/core'; * * const client = new Client({ * url: 'https://API', * exchanges: [cacheExchange, fetchExchange], * }); * * const App = () => ( * * * * ); * ``` */ var Provider = Context.Provider; /** React Consumer component, providing the {@link Client} provided on a parent component. * @remarks * This is an alias for {@link Context.Consumer}. */ var Consumer = Context.Consumer; Context.displayName = 'UrqlContext'; /** Hook returning a {@link Client} from {@link Context}. * * @remarks * `useClient` is a convenience hook, which accesses `urql`'s {@link Context} * and returns the {@link Client} defined on it. * * This will be the {@link Client} you passed to a {@link Provider} * you wrapped your elements containing this hook with. * * @throws * In development, if the component you call `useClient()` in is * not wrapped in a {@link Provider}, an error is thrown. */ var useClient = () => { var client = React.useContext(Context); if (client === OBJ && process.env.NODE_ENV !== 'production') { var error = "No client has been specified using urql's Provider. please create a client and add a Provider."; console.error(error); throw new Error(error); } return client; }; var initialState = { fetching: false, stale: false, hasNext: false, error: undefined, data: undefined, extensions: undefined, operation: undefined }; // Two operations are considered equal if they have the same key var areOperationsEqual = (a, b) => { return a === b || !!(a && b && a.key === b.key); }; /** * Checks if two objects are shallowly different with a special case for * 'operation' where it compares the key if they are not the otherwise equal */ var isShallowDifferent = (a, b) => { for (var key in a) if (!(key in b)) return true; for (var _key in b) { if (_key === 'operation' ? !areOperationsEqual(a[_key], b[_key]) : a[_key] !== b[_key]) { return true; } } return false; }; var computeNextState = (prevState, result) => { var newState = { ...prevState, ...result, data: result.data !== undefined || result.error ? result.data : prevState.data, fetching: !!result.fetching, stale: !!result.stale }; return isShallowDifferent(prevState, newState) ? newState : prevState; }; var hasDepsChanged = (a, b) => { for (var i = 0, l = b.length; i < l; i++) if (a[i] !== b[i]) return true; return false; }; var reactSharedInternals = React.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED; function deferDispatch(setState, value) { if (process.env.NODE_ENV !== 'production' && !!reactSharedInternals && !!reactSharedInternals.ReactCurrentOwner && !!reactSharedInternals.ReactCurrentOwner.current) { Promise.resolve(value).then(setState); } else { setState(value); } } /** State of the last mutation executed by your {@link useMutation} hook. * * @remarks * `UseMutationState` is returned (in a tuple) by {@link useMutation} and * gives you the {@link OperationResult} of the last mutation executed * with {@link UseMutationExecute}. * * Even if the mutation document passed to {@link useMutation} changes, * the state isn’t reset, so you can keep displaying the previous result. */ /** Triggers {@link useMutation} to execute its GraphQL mutation operation. * * @param variables - variables using which the mutation will be executed. * @param context - optionally, context options that will be merged with the hook's * {@link UseQueryArgs.context} options and the `Client`’s options. * @returns the {@link OperationResult} of the mutation. * * @remarks * When called, {@link useMutation} will start the GraphQL mutation * it currently holds and use the `variables` passed to it. * * Once the mutation response comes back from the API, its * returned promise will resolve to the mutation’s {@link OperationResult} * and the {@link UseMutationState} will be updated with the result. * * @example * ```ts * const [result, executeMutation] = useMutation(UpdateTodo); * const start = async ({ id, title }) => { * const result = await executeMutation({ id, title }); * }; */ /** Result tuple returned by the {@link useMutation} hook. * * @remarks * Similarly to a `useState` hook’s return value, * the first element is the {@link useMutation}’s state, updated * as mutations are executed with the second value, which is * used to start mutations and is a {@link UseMutationExecute} * function. */ /** Hook to create a GraphQL mutation, run by passing variables to the returned execute function. * * @param query - a GraphQL mutation document which `useMutation` will execute. * @returns a {@link UseMutationResponse} tuple of a {@link UseMutationState} result, * and an execute function to start the mutation. * * @remarks * `useMutation` allows GraphQL mutations to be defined and keeps its state * after the mutation is started with the returned execute function. * * Given a GraphQL mutation document it returns state to keep track of the * mutation state and a {@link UseMutationExecute} function, which accepts * variables for the mutation to be executed. * Once called, the mutation executes and the state will be updated with * the mutation’s result. * * @see {@link https://urql.dev/goto/urql/docs/basics/react-preact/#mutations} for `useMutation` docs. * * @example * ```ts * import { gql, useMutation } from 'urql'; * * const UpdateTodo = gql` * mutation ($id: ID!, $title: String!) { * updateTodo(id: $id, title: $title) { * id, title * } * } * `; * * const UpdateTodo = () => { * const [result, executeMutation] = useMutation(UpdateTodo); * const start = async ({ id, title }) => { * const result = await executeMutation({ id, title }); * }; * // ... * }; * ``` */ function useMutation(query) { var isMounted = React.useRef(true); var client = useClient(); var [state, setState] = React.useState(initialState); var executeMutation = React.useCallback((variables, context) => { deferDispatch(setState, { ...initialState, fetching: true }); return wonka.toPromise(wonka.take(1)(wonka.filter(result => !result.hasNext)(wonka.onPush(result => { if (isMounted.current) { deferDispatch(setState, { fetching: false, stale: result.stale, data: result.data, error: result.error, extensions: result.extensions, operation: result.operation, hasNext: result.hasNext }); } })(client.executeMutation(core.createRequest(query, variables), context || {}))))); }, // eslint-disable-next-line react-hooks/exhaustive-deps [client, query, setState]); React.useEffect(() => { isMounted.current = true; return () => { isMounted.current = false; }; }, []); return [state, executeMutation]; } /** Creates a request from a query and variables but preserves reference equality if the key isn't changing * @internal */ function useRequest(query, variables) { var prev = React.useRef(undefined); return React.useMemo(() => { var request = core.createRequest(query, variables); // We manually ensure reference equality if the key hasn't changed if (prev.current !== undefined && prev.current.key === request.key) { return prev.current; } else { prev.current = request; return request; } }, [query, variables]); } var getCacheForClient = client => { if (!client._react) { var reclaim = new Set(); var map = new Map(); if (client.operations$ /* not available in mocks */) { wonka.subscribe(operation => { if (operation.kind === 'teardown' && reclaim.has(operation.key)) { reclaim.delete(operation.key); map.delete(operation.key); } })(client.operations$); } client._react = { get(key) { return map.get(key); }, set(key, value) { reclaim.delete(key); map.set(key, value); }, dispose(key) { reclaim.add(key); } }; } return client._react; }; /* eslint-disable react-hooks/exhaustive-deps */ /** Input arguments for the {@link useQuery} hook. * * @param query - The GraphQL query that `useQuery` executes. * @param variables - The variables for the GraphQL query that `useQuery` executes. */ /** State of the current query, your {@link useQuery} hook is executing. * * @remarks * `UseQueryState` is returned (in a tuple) by {@link useQuery} and * gives you the updating {@link OperationResult} of GraphQL queries. * * Even when the query and variables passed to {@link useQuery} change, * this state preserves the prior state and sets the `fetching` flag to * `true`. * This allows you to display the previous state, while implementing * a separate loading indicator separately. */ /** Triggers {@link useQuery} to execute a new GraphQL query operation. * * @param opts - optionally, context options that will be merged with the hook's * {@link UseQueryArgs.context} options and the `Client`’s options. * * @remarks * When called, {@link useQuery} will re-execute the GraphQL query operation * it currently holds, even if {@link UseQueryArgs.pause} is set to `true`. * * This is useful for executing a paused query or re-executing a query * and get a new network result, by passing a new request policy. * * ```ts * const [result, reexecuteQuery] = useQuery({ query }); * * const refresh = () => { * // Re-execute the query with a network-only policy, skipping the cache * reexecuteQuery({ requestPolicy: 'network-only' }); * }; * ``` */ /** Result tuple returned by the {@link useQuery} hook. * * @remarks * Similarly to a `useState` hook’s return value, * the first element is the {@link useQuery}’s result and state, * a {@link UseQueryState} object, * and the second is used to imperatively re-execute the query * via a {@link UseQueryExecute} function. */ var isSuspense = (client, context) => context && context.suspense !== undefined ? !!context.suspense : client.suspense; /** Hook to run a GraphQL query and get updated GraphQL results. * * @param args - a {@link UseQueryArgs} object, to pass a `query`, `variables`, and options. * @returns a {@link UseQueryResponse} tuple of a {@link UseQueryState} result, and re-execute function. * * @remarks * `useQuery` allows GraphQL queries to be defined and executed. * Given {@link UseQueryArgs.query}, it executes the GraphQL query with the * context’s {@link Client}. * * The returned result updates when the `Client` has new results * for the query, and changes when your input `args` change. * * Additionally, if the `suspense` option is enabled on the `Client`, * the `useQuery` hook will suspend instead of indicating that it’s * waiting for a result via {@link UseQueryState.fetching}. * * @see {@link https://urql.dev/goto/urql/docs/basics/react-preact/#queries} for `useQuery` docs. * * @example * ```ts * import { gql, useQuery } from 'urql'; * * const TodosQuery = gql` * query { todos { id, title } } * `; * * const Todos = () => { * const [result, reexecuteQuery] = useQuery({ * query: TodosQuery, * variables: {}, * }); * // ... * }; * ``` */ function useQuery(args) { var client = useClient(); var cache = getCacheForClient(client); var suspense = isSuspense(client, args.context); var request = useRequest(args.query, args.variables); var source = React.useMemo(() => { if (args.pause) return null; var source = client.executeQuery(request, { requestPolicy: args.requestPolicy, ...args.context }); return suspense ? wonka.onPush(result => { cache.set(request.key, result); })(source) : source; }, [cache, client, request, suspense, args.pause, args.requestPolicy, args.context]); var getSnapshot = React.useCallback((source, suspense) => { if (!source) return { fetching: false }; var result = cache.get(request.key); if (!result) { var resolve; var subscription = wonka.subscribe(_result => { result = _result; if (resolve) resolve(result); })(wonka.takeWhile(() => suspense && !resolve || !result || 'hasNext' in result && result.hasNext)(source)); if (result == null && suspense) { var promise = new Promise(_resolve => { resolve = _resolve; }); cache.set(request.key, promise); throw promise; } else { subscription.unsubscribe(); } } else if (suspense && result != null && 'then' in result) { throw result; } return result || { fetching: true }; }, [cache, request]); var deps = [client, request, args.requestPolicy, args.context, args.pause]; var [state, setState] = React.useState(() => [source, computeNextState(initialState, getSnapshot(source, suspense)), deps]); var currentResult = state[1]; if (source !== state[0] && hasDepsChanged(state[2], deps)) { setState([source, currentResult = computeNextState(state[1], getSnapshot(source, suspense)), deps]); } React.useEffect(() => { var source = state[0]; var request = state[2][1]; var hasResult = false; var updateResult = result => { hasResult = true; deferDispatch(setState, state => { var nextResult = computeNextState(state[1], result); return state[1] !== nextResult ? [state[0], nextResult, state[2]] : state; }); }; if (source) { var subscription = wonka.subscribe(updateResult)(wonka.onEnd(() => { updateResult({ fetching: false }); })(source)); if (!hasResult) updateResult({ fetching: true }); return () => { cache.dispose(request.key); subscription.unsubscribe(); }; } else { updateResult({ fetching: false }); } }, [cache, state[0], state[2][1]]); var executeQuery = React.useCallback(opts => { var context = { requestPolicy: args.requestPolicy, ...args.context, ...opts }; deferDispatch(setState, state => { var source = suspense ? wonka.onPush(result => { cache.set(request.key, result); })(client.executeQuery(request, context)) : client.executeQuery(request, context); return [source, state[1], deps]; }); }, [client, cache, request, suspense, args.requestPolicy, args.context, args.pause]); return [currentResult, executeQuery]; } /* eslint-disable react-hooks/exhaustive-deps */ /** Input arguments for the {@link useSubscription} hook. * * @param query - The GraphQL subscription document that `useSubscription` executes. * @param variables - The variables for the GraphQL subscription that `useSubscription` executes. */ /** Combines previous data with an incoming subscription result’s data. * * @remarks * A `SubscriptionHandler` may be passed to {@link useSubscription} to * aggregate subscription results into a combined {@link UseSubscriptionState.data} * value. * * This is useful when a subscription event delivers a single item, while * you’d like to display a list of events. * * @example * ```ts * const NotificationsSubscription = gql` * subscription { newNotification { id, text } } * `; * * const combineNotifications = (notifications = [], data) => { * return [...notifications, data.newNotification]; * }; * * const [result, executeSubscription] = useSubscription( * { query: NotificationsSubscription }, * combineNotifications, * ); * ``` */ /** State of the current subscription, your {@link useSubscription} hook is executing. * * @remarks * `UseSubscriptionState` is returned (in a tuple) by {@link useSubscription} and * gives you the updating {@link OperationResult} of GraphQL subscriptions. * * If a {@link SubscriptionHandler} has been passed to `useSubscription` then * {@link UseSubscriptionState.data} is instead the updated data as returned * by the handler, otherwise it’s the latest result’s data. * * Hint: Even when the query and variables passed to {@link useSubscription} change, * this state preserves the prior state. */ /** Triggers {@link useSubscription} to reexecute a GraphQL subscription operation. * * @param opts - optionally, context options that will be merged with the hook's * {@link UseSubscriptionArgs.context} options and the `Client`’s options. * * @remarks * When called, {@link useSubscription} will restart the GraphQL subscription * operation it currently holds. If {@link UseSubscriptionArgs.pause} is set * to `true`, it will start executing the subscription. * * ```ts * const [result, executeSubscription] = useSubscription({ * query, * pause: true, * }); * * const start = () => { * executeSubscription(); * }; * ``` */ /** Result tuple returned by the {@link useSubscription} hook. * * @remarks * Similarly to a `useState` hook’s return value, * the first element is the {@link useSubscription}’s state, * a {@link UseSubscriptionState} object, * and the second is used to imperatively re-execute or start the subscription * via a {@link UseMutationExecute} function. */ /** Hook to run a GraphQL subscription and get updated GraphQL results. * * @param args - a {@link UseSubscriptionArgs} object, to pass a `query`, `variables`, and options. * @param handler - optionally, a {@link SubscriptionHandler} function to combine multiple subscription results. * @returns a {@link UseSubscriptionResponse} tuple of a {@link UseSubscriptionState} result, and an execute function. * * @remarks * `useSubscription` allows GraphQL subscriptions to be defined and executed. * Given {@link UseSubscriptionArgs.query}, it executes the GraphQL subscription with the * context’s {@link Client}. * * The returned result updates when the `Client` has new results * for the subscription, and `data` is updated with the result’s data * or with the `data` that a `handler` returns. * * @example * ```ts * import { gql, useSubscription } from 'urql'; * * const NotificationsSubscription = gql` * subscription { newNotification { id, text } } * `; * * const combineNotifications = (notifications = [], data) => { * return [...notifications, data.newNotification]; * }; * * const Notifications = () => { * const [result, executeSubscription] = useSubscription( * { query: NotificationsSubscription }, * combineNotifications, * ); * // ... * }; * ``` */ function useSubscription(args, handler) { var client = useClient(); var request = useRequest(args.query, args.variables); var handlerRef = React.useRef(handler); handlerRef.current = handler; var source = React.useMemo(() => !args.pause ? client.executeSubscription(request, args.context) : null, [client, request, args.pause, args.context]); var deps = [client, request, args.context, args.pause]; var [state, setState] = React.useState(() => [source, { ...initialState, fetching: !!source }, deps]); var currentResult = state[1]; if (source !== state[0] && hasDepsChanged(state[2], deps)) { setState([source, currentResult = computeNextState(state[1], { fetching: !!source }), deps]); } React.useEffect(() => { var updateResult = result => { deferDispatch(setState, state => { var nextResult = computeNextState(state[1], result); if (state[1] === nextResult) return state; if (handlerRef.current && nextResult.data != null && state[1].data !== nextResult.data) { nextResult.data = handlerRef.current(state[1].data, nextResult.data); } return [state[0], nextResult, state[2]]; }); }; if (state[0]) { return wonka.subscribe(updateResult)(wonka.onEnd(() => { updateResult({ fetching: !!source }); })(state[0])).unsubscribe; } else { updateResult({ fetching: false }); } }, [state[0]]); // This is the imperative execute function passed to the user var executeSubscription = React.useCallback(opts => { var source = client.executeSubscription(request, { ...args.context, ...opts }); deferDispatch(setState, state => [source, state[1], deps]); }, [client, request, args.context, args.pause]); return [currentResult, executeSubscription]; } /** Props accepted by {@link Mutation}. * * @remarks * `MutationProps` are the props accepted by the {@link Mutation} component. * * The result, the {@link MutationState} object, will be passed to * a {@link MutationProps.children} function, passed as children * to the `Mutation` component. */ /** Object that {@link MutationProps.children} is called with. * * @remarks * This is an extented {@link UseMutationstate} with an added * {@link MutationState.executeMutation} method, which is usually * part of a tuple returned by {@link useMutation}. */ /** Component Wrapper around {@link useMutation} to run a GraphQL query. * * @remarks * `Mutation` is a component wrapper around the {@link useMutation} hook * that calls the {@link MutationProps.children} prop, as a function, * with the {@link MutationState} object. */ function Mutation(props) { var mutation = useMutation(props.query); return props.children({ ...mutation[0], executeMutation: mutation[1] }); } /** Props accepted by {@link Query}. * * @remarks * `QueryProps` are the props accepted by the {@link Query} component, * which is identical to {@link UseQueryArgs}. * * The result, the {@link QueryState} object, will be passed to * a {@link QueryProps.children} function, passed as children * to the `Query` component. */ /** Object that {@link QueryProps.children} is called with. * * @remarks * This is an extented {@link UseQueryState} with an added * {@link QueryState.executeQuery} method, which is usually * part of a tuple returned by {@link useQuery}. */ /** Component Wrapper around {@link useQuery} to run a GraphQL query. * * @remarks * `Query` is a component wrapper around the {@link useQuery} hook * that calls the {@link QueryProps.children} prop, as a function, * with the {@link QueryState} object. */ function Query(props) { var query = useQuery(props); return props.children({ ...query[0], executeQuery: query[1] }); } /** Props accepted by {@link Subscription}. * * @remarks * `SubscriptionProps` are the props accepted by the {@link Subscription} component, * which is identical to {@link UseSubscriptionArgs} with an added * {@link SubscriptionProps.handler} prop, which {@link useSubscription} usually * accepts as an additional argument. * * The result, the {@link SubscriptionState} object, will be passed to * a {@link SubscriptionProps.children} function, passed as children * to the `Subscription` component. */ /** Object that {@link SubscriptionProps.children} is called with. * * @remarks * This is an extented {@link UseSubscriptionState} with an added * {@link SubscriptionState.executeSubscription} method, which is usually * part of a tuple returned by {@link useSubscription}. */ /** Component Wrapper around {@link useSubscription} to run a GraphQL subscription. * * @remarks * `Subscription` is a component wrapper around the {@link useSubscription} hook * that calls the {@link SubscriptionProps.children} prop, as a function, * with the {@link SubscriptionState} object. */ function Subscription(props) { var subscription = useSubscription(props, props.handler); return props.children({ ...subscription[0], executeSubscription: subscription[1] }); } exports.Consumer = Consumer; exports.Context = Context; exports.Mutation = Mutation; exports.Provider = Provider; exports.Query = Query; exports.Subscription = Subscription; exports.useClient = useClient; exports.useMutation = useMutation; exports.useQuery = useQuery; exports.useSubscription = useSubscription; Object.keys(core).forEach(function (k) { if (k !== 'default' && !Object.prototype.hasOwnProperty.call(exports, k)) Object.defineProperty(exports, k, { enumerable: true, get: function () { return core[k]; } }); }); //# sourceMappingURL=urql.js.map