1- import type { AFunction , Prefix } from "../types" ;
1+ import type { AFunction , Prefix , SharedCreated } from "../types" ;
22import { useMemo , useSyncExternalStore } from "react" ;
33import { SharedApi , SharedData } from "../SharedData" ;
44import useShared from "./use-shared" ;
5- import { ensureNonEmptyString } from "../lib/utils" ;
5+ import { ensureNonEmptyString , random } from "../lib/utils" ;
66
77type SharedFunctionsState < T > = {
88 fnState : {
@@ -49,21 +49,60 @@ const sharedFunctionsData = new SharedFunctionsData();
4949
5050export const sharedFunctionsApi = new SharedFunctionsApi ( sharedFunctionsData ) ;
5151
52- export const useSharedFunction = < T , Args extends unknown [ ] , S extends string = string > ( key : S , fn : AFunction < T , Args > , scopeName ?: Prefix ) => {
52+ interface SharedFunctionCreated < T , Args extends unknown [ ] > extends SharedCreated {
53+ fn : AFunction < T , Args >
54+ }
55+
56+ export const createSharedFunction = < T , Args extends unknown [ ] > ( fn : AFunction < T , Args > , scopeName ?: Prefix ) : SharedFunctionCreated < T , Args > => {
57+ const prefix : Prefix = scopeName ?? scopeName ?? "_global" ;
5358
54- key = ensureNonEmptyString ( key ) ;
55- const { prefix} = useShared ( scopeName ) ;
59+ return {
60+ key : random ( ) ,
61+ prefix,
62+ fn,
63+ }
64+ }
65+
66+ export type SharedFunctionStateReturn < T , Args extends unknown [ ] > = {
67+ readonly state : NonNullable < SharedFunctionsState < T > [ 'fnState' ] > ,
68+ readonly trigger : ( ...args : Args ) => void ,
69+ readonly forceTrigger : ( ...args : Args ) => void ,
70+ readonly clear : ( ) => void ,
71+ }
72+
73+ export function useSharedFunction < T , Args extends unknown [ ] , S extends string = string > ( key : S , fn : AFunction < T , Args > , scopeName ?: Prefix ) : SharedFunctionStateReturn < T , Args > ;
74+ export function useSharedFunction < T , Args extends unknown [ ] > ( sharedFunctionCreated : SharedFunctionCreated < T , Args > ) : SharedFunctionStateReturn < T , Args > ;
75+ export function useSharedFunction < T , Args extends unknown [ ] , S extends string = string > (
76+ key : S | SharedFunctionCreated < T , Args > ,
77+ fn ?: AFunction < T , Args > ,
78+ scopeName ?: Prefix
79+ ) : SharedFunctionStateReturn < T , Args > {
80+
81+ let keyStr : string ;
82+ let fnVal ! : AFunction < T , Args > ;
83+ let scope : Prefix | undefined = scopeName ;
84+
85+ if ( typeof key !== "string" ) {
86+ const { key : key2 , fn : fn2 , prefix : prefix2 } = key ;
87+ keyStr = key2 ;
88+ fnVal = fn2 ;
89+ scope = prefix2 ;
90+ } else {
91+ keyStr = ensureNonEmptyString ( key ) ;
92+ fnVal = fn as AFunction < T , Args > ;
93+ }
94+ const { prefix} = useShared ( scope ) ;
5695
57- sharedFunctionsData . init ( key , prefix ) ;
96+ sharedFunctionsData . init ( keyStr , prefix ) ;
5897
5998 const externalStoreSubscriber = useMemo < Parameters < typeof useSyncExternalStore < NonNullable < SharedFunctionsState < T > [ 'fnState' ] > > > [ 0 ] > (
6099 ( ) =>
61100 ( listener ) => {
62- sharedFunctionsData . init ( key , prefix ) ;
63- sharedFunctionsData . addListener ( key , prefix , listener ) ;
101+ sharedFunctionsData . init ( keyStr , prefix ) ;
102+ sharedFunctionsData . addListener ( keyStr , prefix , listener ) ;
64103
65104 return ( ) => {
66- sharedFunctionsData . removeListener ( key , prefix , listener ) ;
105+ sharedFunctionsData . removeListener ( keyStr , prefix , listener ) ;
67106 }
68107 } ,
69108 [ ]
@@ -72,27 +111,27 @@ export const useSharedFunction = <T, Args extends unknown[], S extends string =
72111 const externalStoreSnapshotGetter = useMemo < Parameters < typeof useSyncExternalStore < NonNullable < SharedFunctionsState < T > [ 'fnState' ] > > > [ 1 ] > (
73112 ( ) =>
74113 ( ) =>
75- sharedFunctionsData . get ( key , prefix ) ! . fnState as NonNullable < SharedFunctionsState < T > [ 'fnState' ] > ,
114+ sharedFunctionsData . get ( keyStr , prefix ) ! . fnState as NonNullable < SharedFunctionsState < T > [ 'fnState' ] > ,
76115 [ ]
77116 ) ;
78117
79118 const state = useSyncExternalStore < NonNullable < SharedFunctionsState < T > [ 'fnState' ] > > ( externalStoreSubscriber , externalStoreSnapshotGetter ) ;
80119
81120 const trigger = async ( force : boolean , ...args : Args ) => {
82- const entry = sharedFunctionsData . get ( key , prefix ) ! ;
121+ const entry = sharedFunctionsData . get ( keyStr , prefix ) ! ;
83122 if ( ! force && ( entry . fnState . isLoading || entry . fnState . results !== undefined ) ) return entry . fnState ;
84123 entry . fnState = { ...entry . fnState , isLoading : true , error : undefined } ;
85124 entry . listeners . forEach ( l => l ( ) ) ;
86125 try {
87- const results : Awaited < T > = await fn ( ...args ) ;
126+ const results : Awaited < T > = await fnVal ( ...args ) ;
88127 entry . fnState = { results, isLoading : false , error : undefined } ;
89128 } catch ( error ) {
90129 entry . fnState = { ...entry . fnState , isLoading : false , error } ;
91130 }
92131 entry . listeners . forEach ( l => l ( ) ) ;
93132 } ;
94133
95- sharedFunctionsData . useEffect ( key , prefix ) ;
134+ sharedFunctionsData . useEffect ( keyStr , prefix ) ;
96135
97136 // noinspection JSUnusedGlobalSymbols
98137 return {
@@ -104,8 +143,8 @@ export const useSharedFunction = <T, Args extends unknown[], S extends string =
104143 void trigger ( true , ...args ) ;
105144 } ,
106145 clear : ( ) => {
107- sharedFunctionsData . clear ( key , prefix ) ;
108- sharedFunctionsData . init ( key , prefix ) ;
146+ sharedFunctionsData . clear ( keyStr , prefix ) ;
147+ sharedFunctionsData . init ( keyStr , prefix ) ;
109148 }
110149 } as const ;
111- } ;
150+ }
0 commit comments