-
Notifications
You must be signed in to change notification settings - Fork 6
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(react): multichain query hooks (#515)
- Loading branch information
Showing
19 changed files
with
557 additions
and
79 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
--- | ||
"@reactive-dot/react": minor | ||
--- | ||
|
||
Added concurrent multi-chain query capability hooks. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Binary file not shown.
Binary file not shown.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
import { useChainId, useLazyLoadQuery } from "@reactive-dot/react"; | ||
import { useMemo } from "react"; | ||
|
||
export function MultichainQuery() { | ||
const chainId = useChainId(); | ||
|
||
const [parachains, assetHubParaId] = useLazyLoadQuery([ | ||
{ | ||
chainId: undefined, | ||
query: (builder) => builder.readStorage("Paras", "Parachains", []), | ||
}, | ||
{ | ||
chainId: useMemo(() => { | ||
switch (chainId) { | ||
case "polkadot": | ||
case "polkadot_asset_hub": | ||
case "polkadot_people": | ||
return "polkadot_asset_hub"; | ||
case "kusama": | ||
case "kusama_asset_hub": | ||
return "kusama_asset_hub"; | ||
case "westend": | ||
case "westend_asset_hub": | ||
return "westend_asset_hub"; | ||
} | ||
}, [chainId]), | ||
query: (builder) => | ||
builder.readStorage("ParachainInfo", "ParachainId", []), | ||
}, | ||
]); | ||
|
||
return ( | ||
<dl> | ||
<dt>Parachain IDs</dt> | ||
<dd>{parachains.join()}</dd> | ||
<dt>Asset Hub ID</dt> | ||
<dd>{assetHubParaId.toString()}</dd> | ||
</dl> | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,65 @@ | ||
import { ChainIdContext } from "../contexts/chain.js"; | ||
import { useQueryOptions } from "./use-query-options.js"; | ||
import { Query, ReactiveDotError } from "@reactive-dot/core"; | ||
import { renderHook } from "@testing-library/react"; | ||
import { expect, it } from "vitest"; | ||
|
||
it("throws error when no chainId is provided", () => { | ||
const renderFunction = () => | ||
renderHook(() => useQueryOptions((q: Query) => q)); | ||
|
||
expect(renderFunction).toThrow(ReactiveDotError); | ||
expect(renderFunction).toThrow("No chain ID provided"); | ||
}); | ||
|
||
it("handles single query with context chainId", () => { | ||
const chainId = 1; | ||
const wrapper = ({ children }: { children: React.ReactNode }) => ( | ||
<ChainIdContext value={chainId}>{children}</ChainIdContext> | ||
); | ||
|
||
const { result } = renderHook(() => useQueryOptions((q: Query) => q), { | ||
wrapper, | ||
}); | ||
|
||
expect(result.current).toHaveLength(1); | ||
expect(result.current[0].chainId).toBe(chainId); | ||
expect(result.current[0].query).toBeInstanceOf(Query); | ||
}); | ||
|
||
it("handles single query with explicit chainId", () => { | ||
const chainId = 1; | ||
const { result } = renderHook(() => | ||
useQueryOptions((q: Query) => q, { chainId }), | ||
); | ||
|
||
expect(result.current).toHaveLength(1); | ||
expect(result.current[0].chainId).toBe(chainId); | ||
expect(result.current[0].query).toBeInstanceOf(Query); | ||
}); | ||
|
||
it("handles multiple queries with different chainIds", () => { | ||
const options = [ | ||
{ chainId: 1, query: (q: Query) => q }, | ||
{ chainId: 2, query: (q: Query) => q }, | ||
]; | ||
|
||
const { result } = renderHook(() => useQueryOptions(options)); | ||
|
||
expect(result.current).toHaveLength(2); | ||
expect(result.current[0].chainId).toBe(1); | ||
expect(result.current[1].chainId).toBe(2); | ||
expect(result.current[0].query).toBeInstanceOf(Query); | ||
expect(result.current[1].query).toBeInstanceOf(Query); | ||
}); | ||
|
||
it("handles Query instance directly", () => { | ||
const chainId = 1; | ||
const query = new Query(); | ||
|
||
const { result } = renderHook(() => useQueryOptions(query, { chainId })); | ||
|
||
expect(result.current).toHaveLength(1); | ||
expect(result.current[0].chainId).toBe(chainId); | ||
expect(result.current[0].query).toBe(query); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,74 @@ | ||
import { ChainIdContext } from "../contexts/chain.js"; | ||
import type { QueryArgument, ChainHookOptions, QueryOptions } from "./types.js"; | ||
import { type ChainId, Query, ReactiveDotError } from "@reactive-dot/core"; | ||
import { use, useMemo } from "react"; | ||
|
||
/** | ||
* @internal | ||
*/ | ||
export function useQueryOptions< | ||
TChainId extends ChainId | undefined, | ||
TQuery extends QueryArgument<TChainId>, | ||
>( | ||
query: TQuery, | ||
options?: ChainHookOptions<TChainId>, | ||
): Array<{ | ||
chainId: ChainId; | ||
// eslint-disable-next-line @typescript-eslint/no-explicit-any | ||
query: Query<any[], any> | undefined; | ||
}>; | ||
/** | ||
* @internal | ||
*/ | ||
export function useQueryOptions< | ||
TChainIds extends Array<ChainId | undefined>, | ||
const TOptions extends { | ||
[P in keyof TChainIds]: QueryOptions<TChainIds[P]>; | ||
}, | ||
>( | ||
options: TOptions & { | ||
[P in keyof TChainIds]: QueryOptions<TChainIds[P]>; | ||
}, | ||
): Array<{ | ||
chainId: ChainId; | ||
// eslint-disable-next-line @typescript-eslint/no-explicit-any | ||
query: Query<any[], any> | undefined; | ||
}>; | ||
/** | ||
* @internal | ||
*/ | ||
export function useQueryOptions( | ||
queryOrOptions: // eslint-disable-next-line @typescript-eslint/no-explicit-any | ||
| QueryArgument<any> | ||
// eslint-disable-next-line @typescript-eslint/no-explicit-any | ||
| Array<ChainHookOptions<any> & { query: QueryArgument<any> }>, | ||
// eslint-disable-next-line @typescript-eslint/no-explicit-any | ||
mayBeOptions?: ChainHookOptions<any>, | ||
) { | ||
const contextChainId = use(ChainIdContext); | ||
|
||
return useMemo( | ||
() => | ||
(Array.isArray(queryOrOptions) | ||
? queryOrOptions | ||
: [{ query: queryOrOptions, ...mayBeOptions }] | ||
).map((options) => { | ||
const chainId = options.chainId ?? contextChainId; | ||
|
||
if (chainId === undefined) { | ||
throw new ReactiveDotError("No chain ID provided"); | ||
} | ||
|
||
return { | ||
chainId, | ||
query: | ||
options.query instanceof Query | ||
? options.query | ||
: typeof options.query === "function" | ||
? options.query(new Query()) || undefined | ||
: undefined, | ||
}; | ||
}), | ||
[contextChainId, mayBeOptions, queryOrOptions], | ||
); | ||
} |
Oops, something went wrong.