Skip to content

Commit

Permalink
Add actor hooks for interacting with actors in IC projects
Browse files Browse the repository at this point in the history
  • Loading branch information
b3hr4d committed Feb 21, 2024
1 parent acf8b5d commit f9e8b0c
Show file tree
Hide file tree
Showing 2 changed files with 103 additions and 1 deletion.
19 changes: 18 additions & 1 deletion packages/react/src/helpers/actor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,23 @@ const DEFAULT_STATE: ActorCallState<never, never> = {
error: undefined,
loading: false,
}

/**
* Provides a set of React hooks designed for interacting with actors in an Internet Computer (IC) project using the React framework and Zustand for state management.
*
* @param actorManager An instance of ActorManager containing methods and properties to manage actors, including the actorStore, canisterId, visitFunction, callMethod, and initialize function.
* @returns An object containing several hooks and utility functions for interacting with actors, managing state, and invoking actor methods.
*
* Hooks included:
* - initialize: Function to initialize actor management.
* - useActorState: Hook for accessing the actor's state including the canister ID.
* - useVisitMethod: Hook for memoizing a method visit service for a given actor method name.
* - useReactorCall: Hook for making calls to actor methods with support for loading states, errors, and custom event handlers.
* - useQueryCall: Hook specifically designed for query calls to actors with features such as automatic refetching on mount and at specified intervals.
* - useUpdateCall: Alias for useReactorCall, tailored for update calls to actors.
* - useMethodCall: Combines useVisitMethod and useReactorCall for a streamlined experience when calling actor methods, including visitation and state management.
*
* Each hook is designed to simplify the process of interacting with actors in IC projects by abstracting away the complexity of state management, error handling, and method invocation.
*/
export const getActorHooks = <A = BaseActor>(
actorManager: ActorManager<A>
): ActorHooks<A> => {
Expand All @@ -47,6 +63,7 @@ export const getActorHooks = <A = BaseActor>(
): VisitService<A>[M] => {
return useMemo(() => visitFunction[functionName], [functionName])
}

const useReactorCall: ReactorCall<A> = ({
args = [],
functionName,
Expand Down
85 changes: 85 additions & 0 deletions packages/react/src/provider/actor/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -82,20 +82,105 @@ export function createReactorContext<Actor = BaseActor>({

const initialize = () => useActorContext().initialize()

/**
* Hook for accessing the current state of the actor, including the canister ID.
*
* @returns An object containing the current state of the actor from Zustand's store and the canister ID.
* @example
* ```tsx
* function ActorStateComponent() {
* const { canisterId, initializing, error, initialized } = useActorState();
*
* return (
* <div>
* <p>Canister ID: {canisterId}</p>
* <p>Initializing: {initializing.toString()}</p>
* <p>Initialized: {initialized.toString()}</p>
* <p>Error: {error?.message}</p>
* </div>
* );
* }
*```
*/
const useActorState = () => useActorContext().useActorState()

/**
* Hook for making query calls to actors. It supports automatic refetching on component mount and at specified intervals.
*
* @param options Configuration object for the query call, including refetching options and other configurations passed to useReactorCall.
* @returns An object containing the query call function and the current call state (data, error, loading, call, reset).
* @example
* ```tsx
* function QueryCallComponent() {
* const { call, data, loading } = useQueryCall({
* functionName: 'getUserProfile',
* args: ['123'],
* refetchOnMount: true,
* refetchInterval: 5000, // refetch every 5 seconds
* });
*
* if (loading) return <p>Loading profile...</p>;
*
* return (
* <div>
* <p>User Profile: {JSON.stringify(data)}</p>
* <button onClick={call}>Refetch</button>
* </div>
* );
* }
* ```
*/
const useQueryCall = <M extends FunctionName<Actor>>(
args: UseQueryCallArgs<Actor, M>
) => useActorContext().useQueryCall(args)

/**
* Hook for making update calls to actors, handling loading states, and managing errors. It supports custom event handlers for loading, success, and error events.
*
* @param options Configuration object for the actor method call, including the method name, arguments, and event handlers.
* @returns An object containing the method call function, a reset function to reset the call state to its default, and the current call state (data, error, loading, call, reset).
* @example
* ```tsx
* function UpdateCallComponent() {
* const { call, data, loading } = useUpdateCall({
* functionName: 'updateUserProfile',
* args: ['123', { name: 'John Doe' }],
* onLoading: (loading) => console.log('Loading:', loading),
* onError: (error) => console.error('Error:', error),
* onSuccess: (data) => console.log('Success:', data),
* });
*
* if (loading) return <p>Updating profile...</p>;
*
* return (
* <div>
* <p>Updated Profile: {JSON.stringify(data)}</p>
* <button onClick={call}>Update</button>
* </div>
* );
* }
* ```
*/
const useUpdateCall = <M extends FunctionName<Actor>>(
args: UseUpdateCallArgs<Actor, M>
) => useActorContext().useUpdateCall(args)

/**
* Hook that combines useVisitMethod and useReactorCall for calling actor methods. It provides both the visit service for the method and the ability to make actor calls with state management.
*
* @param args Configuration object including the function name and arguments for the actor method call.
* @returns An object containing the visit function for the method and the current call state (data, error, loading).
*/
const useMethodCall = <M extends FunctionName<Actor>>(
args: UseMethodCallArg<Actor, M>
) => useActorContext().useMethodCall(args)

/**
* Memoizes and returns a visit service function for a specific actor method.
*
* @param functionName The name of the actor method to visit.
* @returns The visit service function for the specified method.
*/
const useVisitMethod = (functionName: FunctionName<Actor>) =>
useActorContext().useVisitMethod(functionName)

Expand Down

0 comments on commit f9e8b0c

Please sign in to comment.