-
Notifications
You must be signed in to change notification settings - Fork 1
/
index.tsx
132 lines (122 loc) · 4.39 KB
/
index.tsx
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
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
import React from "react"
import { useActor } from "../../hooks/useActor"
import { extractActorContext } from "../../helpers/extractActorContext"
import type { ActorHooksReturnType, BaseActor } from "../../types"
import type {
CreateActorContextParameters,
CreateActorContextReturnType,
ActorProviderProps,
ActorHookProviderProps,
} from "./types"
/**
* Creates a React context specifically designed for managing the state and interactions with an actor on the Internet Computer (IC) blockchain.
* This context facilitates the dynamic creation and management of IC actors within React applications, leveraging the provided configuration options.
*
* @param reactorParameters A partial configuration object for the actor context, allowing customization and specification of actor-related settings.
* - `canisterId`: The default Canister ID to be used if not overridden in the `ActorProvider` component.
* - Other configurations can include properties related to the actor's interaction, such as agent options or authentication requirements.
*
* @returns An object containing the `ActorProvider` component and various hooks for interacting with the actor.
* - `ActorProvider`: A context provider component that allows child components to access and interact with the configured actor.
* - Hooks: Custom hooks derived from the actor context, facilitating interactions like querying or updating the actor's state.
*
* @example
* ```jsx
* import React from 'react';
* import { createActorContext } from '@ic-reactor/react';
* import { backend, canisterId, idlFactory } from './declarations/candid'; // Assuming 'declarations/candid' is where your actor interface is defined.
*
* // Initialize the actor context with configuration options
* const { ActorProvider, useActorState, useQueryCall, useUpdateCall } = createActorContext<typeof backend>({
* canisterId,
* idlFactory, // Optional, wrap the ActorProvider with CandidAdapterProvider
* });
*
* // A sample component that utilizes the actor context
* const App = () => (
* <AgentProvider>
* <ActorProvider>
* <div>
* <h1>IC Actor Interaction Example</h1>
* <ActorComponent />
* </div>
* </ActorProvider>
* </AgentProvider>
* );
*
* export default App;
*
* // A sample component that uses the actor hooks
* const ActorComponent = () => {
* const { data, loading, error } = useQueryCall({
* functionName: 'backendMethodName',
* args: [],
* refetchInterval: 10000,
* refetchOnMount: true,
* });
* return (
* <div>
* {loading && <p>Loading...</p>}
* {error && <p>Error: {error.message}</p>}
* {data && <p>Actor data: {data}</p>}
* </div>
* );
* };
* ```
*
* This function streamlines the process of setting up a context for IC actor interactions within a React app,
* it provides a type-safe and efficient way to manage actor state and interactions.
*/
export function createActorContext<A = BaseActor>(
contextConfig: CreateActorContextParameters = {}
): CreateActorContextReturnType<A> {
const { canisterId: defaultCanisterId, ...defaultConfig } = contextConfig
const ActorContext = React.createContext<ActorHooksReturnType<A> | null>(null)
const ActorProvider: React.FC<ActorProviderProps> = ({
children,
canisterId = defaultCanisterId,
loadingComponent = <div>Fetching canister...</div>,
authenticatingComponent = <div>Authenticating...</div>,
...restConfig
}) => {
if (!canisterId) {
throw new Error("canisterId is required")
}
const config = React.useMemo(
() => ({
...defaultConfig,
...restConfig,
}),
[defaultConfig, restConfig]
)
const { fetchError, authenticating, hooks } = useActor<A>({
canisterId,
...config,
})
return (
<ActorContext.Provider value={hooks}>
{hooks === null
? fetchError
? fetchError
: authenticating
? authenticatingComponent
: loadingComponent
: children}
</ActorContext.Provider>
)
}
ActorProvider.displayName = "ActorProvider"
const ActorHookProvider: React.FC<ActorHookProviderProps<A>> = ({
hooks,
children,
}) => {
return (
<ActorContext.Provider value={hooks}>{children}</ActorContext.Provider>
)
}
return {
ActorProvider,
ActorHookProvider,
...extractActorContext<A>(ActorContext),
}
}