import { useCallback , useContext , useDebugValue , useEffect , useState } from 'react' ; import { getStatedBeanContext } from '../context' ; import { BeanDefinition , BeanObserver } from '../core' ; import { BeanProvider , ClassType , StateAction } from '../types' ; import { isFunction , isStatedBeanClass } from '../utils' ; export type UseBeanOptions < TProps > = string | symbol | { name ? : string | symbol ; props ? : TProps ; } ; export template T param { ( ClassType < T > | ( ( ) => T ) ) } typeOrSupplier param { ( string | symbol ) } name returns { T } export function useBean < T , TProps = Record < string , unknown > > ( typeOrSupplier , option ? ) { const StateBeanContext = getStatedBeanContext ( ) ; const context = useContext ( StateBeanContext ) ; const [ , setVersion ] = useState ( 0 ) ; let name ; let props ; if ( option !== undefined ) { if ( typeof option === 'object' ) { name = option . name ; props = option . props ; } else if ( typeof option === 'string' || typeof option === 'symbol' ) { name = option ; } } const beanChangeListener = useCallback ( ( _action ) => { setVersion ( prev => prev + 1 ) ; } , [ ] ) ; const container = context . container ; if ( container === undefined ) { throw new Error ( 'not found stated bean container.' ) ; } const [ observer ] = useState ( ( ) => { let provider ; if ( isFunction ( typeOrSupplier ) && ! isStatedBeanClass ( typeOrSupplier ) ) { const supplier = typeOrSupplier as ( ) => T ; const type = supplier . constructor as ClassType < T > ; provider = { type , factory : supplier , name , props } ; } else { provider = { type : typeOrSupplier as ClassType < T > , name , props } ; } return container . register ( new BeanDefinition ( provider ) ) ; } ) ; const [ subscription ] = useState ( ( ) => { return observer . state$ . subscribe ( beanChangeListener ) ; } ) ; useEffect ( ( ) => { observer . props$ . next ( props ) ; } , [ props , observer ] ) ; useEffect ( ( ) => { return ( ) => subscription . unsubscribe ( ) ; } , [ subscription ] ) ; useDebugValue ( observer , ( ob ) => { return { metadata : ob . beanMeta , bean : ob . origin , id : `${ ob . beanDefinition . beanType . name }#${ String ( ob . beanDefinition . beanName ) }` , } ; } ) ; return observer . proxy ; }