jotai
Version:
👻 Next gen state management that will spook you
240 lines (234 loc) • 6.33 kB
JavaScript
import { createClient } from '@urql/core';
import { atom } from 'jotai';
import { pipe, subscribe } from 'wonka';
const DEFAULT_URL = (() => {
try {
return process.env.JOTAI_URQL_DEFAULT_URL;
} catch {
return void 0;
}
})() || "/graphql";
const clientAtom = atom(createClient({ url: DEFAULT_URL }));
const isOperationResultWithData$1 = (result) => "data" in result && !result.error;
function atomWithQuery(createQueryArgs, getClient = (get) => get(clientAtom)) {
const queryResultAtom = atom((get) => {
const args = createQueryArgs(get);
if (args.pause) {
return null;
}
const client = getClient(get);
let resolve = null;
const makePending = () => new Promise((r) => {
resolve = r;
});
const resultAtom = atom(makePending());
let setResult = null;
const listener = (result) => {
if (!resolve && !setResult) {
throw new Error("setting result without mount");
}
if (resolve) {
resolve(result);
resolve = null;
}
if (setResult) {
setResult(result);
}
};
let subscription = null;
let timer;
const startQuery = (opts) => {
if (subscription) {
clearTimeout(timer);
subscription.unsubscribe();
}
subscription = pipe(
client.query(args.query, args.variables, {
...args.requestPolicy && { requestPolicy: args.requestPolicy },
...args.context,
...opts
}),
subscribe(listener)
);
if (!setResult) {
timer = setTimeout(() => {
if (subscription) {
subscription.unsubscribe();
subscription = null;
}
}, 1e3);
}
};
startQuery();
resultAtom.onMount = (update) => {
setResult = update;
if (subscription) {
clearTimeout(timer);
} else {
startQuery();
}
return () => {
setResult = null;
if (subscription) {
subscription.unsubscribe();
subscription = null;
}
};
};
return { resultAtom, makePending, startQuery };
});
const queryAtom = atom(
(get) => {
const queryResult = get(queryResultAtom);
if (!queryResult) {
return null;
}
const { resultAtom } = queryResult;
const result = get(resultAtom);
if (!isOperationResultWithData$1(result)) {
throw result.error;
}
return result;
},
(get, set, action) => {
if (action.type === "reexecute") {
console.warn(
"DEPRECATED [atomWithQuery] use refetch instead of reexecute"
);
action.type = "refetch";
}
switch (action.type) {
case "refetch": {
const queryResult = get(queryResultAtom);
if (!queryResult) {
throw new Error("query is paused");
}
const { resultAtom, makePending, startQuery } = queryResult;
set(resultAtom, makePending());
startQuery(action.opts);
return;
}
}
}
);
return queryAtom;
}
function atomWithMutation(createQuery, getClient = (get) => get(clientAtom)) {
const operationResultAtom = atom(
new Promise(() => {
})
);
const queryResultAtom = atom(
(get) => get(operationResultAtom),
async (get, set, action) => {
set(
operationResultAtom,
new Promise(() => {
})
);
const client = getClient(get);
const query = createQuery(get);
return client.mutation(query, action.variables, action.context).toPromise().then((result) => {
var _a;
(_a = action.callback) == null ? void 0 : _a.call(action, result);
if (result.error) {
throw result.error;
}
set(operationResultAtom, result);
});
}
);
return queryResultAtom;
}
const isOperationResultWithData = (result) => "data" in result && !result.error;
function atomWithSubscription(createSubscriptionArgs, getClient = (get) => get(clientAtom)) {
const queryResultAtom = atom((get) => {
const args = createSubscriptionArgs(get);
if (args.pause) {
return null;
}
const client = getClient(get);
let resolve = null;
const makePending = () => new Promise((r) => {
resolve = r;
});
const resultAtom = atom(makePending());
let setResult = null;
const listener = (result) => {
if (resolve) {
resolve(result);
resolve = null;
}
if (setResult) {
setResult(result);
}
};
let subscription = null;
let timer;
const startSub = () => {
if (subscription) {
clearTimeout(timer);
subscription.unsubscribe();
}
subscription = pipe(
client.subscription(args.query, args.variables, args.context),
subscribe(listener)
);
if (!setResult) {
timer = setTimeout(() => {
if (subscription) {
subscription.unsubscribe();
subscription = null;
}
}, 1e3);
}
};
startSub();
resultAtom.onMount = (update) => {
setResult = update;
if (subscription) {
clearTimeout(timer);
} else {
startSub();
}
return () => {
setResult = null;
if (subscription) {
subscription.unsubscribe();
subscription = null;
}
};
};
return { resultAtom, makePending, startSub };
});
const queryAtom = atom(
(get) => {
const queryResult = get(queryResultAtom);
if (!queryResult) {
return null;
}
const { resultAtom } = queryResult;
const result = get(resultAtom);
if (!isOperationResultWithData(result)) {
throw result.error;
}
return result;
},
(get, set, action) => {
switch (action.type) {
case "refetch": {
const queryResult = get(queryResultAtom);
if (!queryResult) {
throw new Error("query is paused");
}
const { resultAtom, makePending, startSub } = queryResult;
set(resultAtom, makePending());
startSub();
return;
}
}
}
);
return queryAtom;
}
export { atomWithMutation, atomWithQuery, atomWithSubscription, clientAtom };