@saberhq/sail
Version:
Account caching and batched loading for React-based Solana applications.
103 lines • 3.62 kB
JavaScript
import mapValues from "lodash.mapvalues";
import zip from "lodash.zip";
import { startTransition, useEffect, useMemo, useState } from "react";
import { getCacheKeyOfPublicKey, SailAccountParseError, useSail } from "..";
import { useAccountsData } from "../hooks/useAccountsData";
/**
* Makes account parsers from a coder.
* @param parsers
* @returns
*/
export const makeParsersFromCoder = (parsers) => {
return mapValues(parsers, (p) => (info) => p(info.accountInfo.data));
};
/**
* Makes hooks for parsers.
* @param parsers
* @returns
*/
export const makeParserHooks = (parsers) => {
const sailParsers = makeParsersFromCoder(parsers);
return mapValues(sailParsers, (parser) => ({
useSingleData: (key) => useParsedAccountData(key, parser),
useData: (keys) => useParsedAccountsData(keys, parser),
}));
};
/**
* Parses accounts with the given parser.
*
* @deprecated use {@link useBatchedParsedAccounts} instead
* @param keys
* @param parser
* @returns
*/
export const useParsedAccountsData = (keys, parser) => {
const { onError } = useSail();
const data = useAccountsData(keys);
const [parsed, setParsed] = useState(keys.reduce((acc, k) => {
if (k) {
acc[getCacheKeyOfPublicKey(k)] = undefined;
}
return acc;
}, {}));
useEffect(() => {
startTransition(() => {
setParsed((prevParsed) => {
const nextParsed = { ...prevParsed };
zip(keys, data).forEach(([key, datum]) => {
if (datum) {
const key = getCacheKeyOfPublicKey(datum.accountId);
const prevValue = prevParsed[key];
if (prevValue &&
prevValue.raw.length === datum.accountInfo.data.length &&
prevValue.raw.equals(datum.accountInfo.data)) {
// preserve referential equality if buffers are equal
return;
}
try {
const parsed = parser(datum);
nextParsed[key] = {
...datum,
accountInfo: {
...datum.accountInfo,
data: parsed,
},
raw: datum.accountInfo.data,
};
}
catch (e) {
onError(new SailAccountParseError(e, datum));
nextParsed[key] = null;
return;
}
}
if (key && datum === null) {
nextParsed[getCacheKeyOfPublicKey(key)] = null;
}
});
return nextParsed;
});
});
}, [data, keys, onError, parser]);
return useMemo(() => {
return keys.map((k) => {
if (!k) {
return k;
}
return parsed[getCacheKeyOfPublicKey(k)];
});
}, [keys, parsed]);
};
/**
* Loads the parsed data of a single account.
* @returns
*/
export const useParsedAccountData = (key, parser) => {
const theKey = useMemo(() => [key], [key]);
const [data] = useParsedAccountsData(theKey, parser);
return {
loading: key !== undefined && data === undefined,
data,
};
};
//# sourceMappingURL=useParsedAccountsData.js.map