diff --git a/examples/react-systemjs/packages/app/src/App.tsx b/examples/react-systemjs/packages/app/src/App.tsx index 0db61bf7..b1a76aff 100644 --- a/examples/react-systemjs/packages/app/src/App.tsx +++ b/examples/react-systemjs/packages/app/src/App.tsx @@ -1,15 +1,30 @@ import type { FC } from 'react'; -import { useState } from 'react'; +import { useEffect, useMemo, useState } from 'react'; import { OBJECTCLASS } from '@pandino/pandino-api'; -import { ComponentProxy } from '@pandino/react-hooks'; +import { ComponentProxy, useTrackService } from '@pandino/react-hooks'; import { CUSTOM_COMPONENT_INTERFACE_KEY } from '@react-systemjs/component-api'; +import { SOME_SERVICE_INTERFACE_KEY, SomeService } from './service'; export const App: FC = () => { const [firstName] = useState('John'); + const { service: someService } = useTrackService(`(${OBJECTCLASS}=${SOME_SERVICE_INTERFACE_KEY})`); + const text = useMemo(() => someService?.someMethod(), [someService]); + + console.count('Rendering App.'); + + useEffect(() => { + console.info(`SomeService implementation: ${someService}`); + }, [someService]); + + useEffect(() => { + console.info(`text: ${text}`); + }, [text]); return (
fallback for: {firstName}
+
SomeService test: {someService?.someMethod()}
+
Text: {text}
); }; diff --git a/examples/react-systemjs/packages/app/src/main.tsx b/examples/react-systemjs/packages/app/src/main.tsx index 50f4aa93..49bb445b 100644 --- a/examples/react-systemjs/packages/app/src/main.tsx +++ b/examples/react-systemjs/packages/app/src/main.tsx @@ -1,8 +1,11 @@ +import { useState } from 'react'; import { createRoot } from 'react-dom/client'; import Pandino from '@pandino/pandino'; import loaderConfiguration from '@pandino/loader-configuration-dom'; import { PandinoProvider } from '@pandino/react-hooks'; +import { CUSTOM_COMPONENT_INTERFACE_KEY, CustomComponent } from '@react-systemjs/component-api'; import { App } from './App'; +import { SOME_SERVICE_INTERFACE_KEY, SomeServiceImpl } from './service'; const root = createRoot(document.querySelector('#root')!); @@ -13,35 +16,50 @@ const pandino = new Pandino({ await pandino.init(); await pandino.start(); -// export const ComponentOne: CustomComponent = (props) => { -// const [data, setData] = useState<{ firstName: string; lastName?: string }>({ ...props }); -// -// return ( -//
-//

Component One

-//

FirstName: {data.firstName}

-//

LastName: {data.lastName}

-//
-// ); -// }; -// -// const reg = pandino.getBundleContext().registerService(CUSTOM_COMPONENT_INTERFACE_KEY, ComponentOne); -// window.setTimeout(() => { -// reg.unregister(); -// }, 2000); - -(async () => { - const componentOneBundle = await pandino.getBundleContext().installBundle('./component-one.system-manifest.json'); - window.setTimeout(() => { - pandino.uninstallBundle(componentOneBundle as any); +const bundleContext = pandino.getBundleContext(); + +export const ComponentOne: CustomComponent = (props) => { + const [data, setData] = useState<{ firstName: string; lastName?: string }>({ ...props }); + + return ( +
+

Component One

+

FirstName: {data.firstName}

+

LastName: {data.lastName}

+
+ ); +}; + +const reg = bundleContext.registerService(CUSTOM_COMPONENT_INTERFACE_KEY, ComponentOne); +window.setTimeout(() => { + reg.unregister(); window.setTimeout(() => { - pandino.getBundleContext().installBundle('./component-one.system-manifest.json'); + bundleContext.registerService(CUSTOM_COMPONENT_INTERFACE_KEY, ComponentOne); }, 2000); - }, 2000); -})(); +}, 2000); + +// (async () => { +// const componentOneBundle = await bundleContext.installBundle('./component-one.system-manifest.json'); +// window.setTimeout(() => { +// pandino.uninstallBundle(componentOneBundle as any); +// window.setTimeout(() => { +// bundleContext.installBundle('./component-one.system-manifest.json'); +// }, 2000); +// }, 2000); +// })(); + +// (async () => { +// let someReg = await bundleContext.registerService(SOME_SERVICE_INTERFACE_KEY, new SomeServiceImpl()); +// window.setTimeout(async () => { +// someReg.unregister(); +// window.setTimeout(async () => { +// someReg = await bundleContext.registerService(SOME_SERVICE_INTERFACE_KEY, new SomeServiceImpl()); +// }, 2000); +// }, 2000); +// })(); root.render( - + , ); diff --git a/examples/react-systemjs/packages/app/src/service.ts b/examples/react-systemjs/packages/app/src/service.ts new file mode 100644 index 00000000..dffef91f --- /dev/null +++ b/examples/react-systemjs/packages/app/src/service.ts @@ -0,0 +1,11 @@ +export const SOME_SERVICE_INTERFACE_KEY = 'SomeService'; + +export interface SomeService { + someMethod(): string; +} + +export class SomeServiceImpl implements SomeService { + someMethod(): string { + return "some fine service"; + } +} diff --git a/packages/@pandino/pandino-api/src/service/service-utils.ts b/packages/@pandino/pandino-api/src/service/service-utils.ts index c83b6155..2cf09122 100644 --- a/packages/@pandino/pandino-api/src/service/service-utils.ts +++ b/packages/@pandino/pandino-api/src/service/service-utils.ts @@ -1,4 +1,4 @@ -import { ServiceReference } from '../../dist/esm/dist'; +import { ServiceReference } from './service-reference'; export interface ServiceUtils { getBestServiceReference(refs: ServiceReference[]): ServiceReference | undefined; diff --git a/packages/@pandino/react-hooks/src/useTrackService.ts b/packages/@pandino/react-hooks/src/useTrackService.ts index 2aa07922..2ebcaaf8 100644 --- a/packages/@pandino/react-hooks/src/useTrackService.ts +++ b/packages/@pandino/react-hooks/src/useTrackService.ts @@ -1,5 +1,5 @@ import { useBundleContext } from './PandinoContext'; -import { useCallback, useEffect, useState } from 'react'; +import { useCallback, useEffect, useRef, useState } from 'react'; import type { ServiceEvent, ServiceListener, ServiceUtils } from '@pandino/pandino-api'; import { FRAMEWORK_SERVICE_UTILS } from '@pandino/pandino-api'; @@ -10,11 +10,12 @@ export interface SimpleTracker { export type ServiceTrackerHook = (filter: string) => SimpleTracker; export const useTrackService: ServiceTrackerHook = (filter: string) => { + const isInitialMount = useRef(true); const { bundleContext } = useBundleContext(); - const serviceUtilsRef = bundleContext.getServiceReference(FRAMEWORK_SERVICE_UTILS); - const serviceUtils = bundleContext.getService(serviceUtilsRef); const getService = useCallback<(filter: string) => T | undefined>( (filter: string) => { + const serviceUtilsRef = bundleContext.getServiceReference(FRAMEWORK_SERVICE_UTILS); + const serviceUtils = bundleContext.getService(serviceUtilsRef); const refs = bundleContext.getServiceReferences(undefined, filter); const ref = serviceUtils.getBestServiceReference(refs); if (ref) { @@ -41,22 +42,28 @@ export const useTrackService: ServiceTrackerHook = (filter: string) => { }, }; }, [filter]); - const [listener, setListener] = useState(); + const [listener, setListener] = useState(createListener()); useEffect(() => { - if (listener) { - bundleContext.removeServiceListener(listener); - } + if (isInitialMount.current) { + isInitialMount.current = false; + bundleContext.addServiceListener(listener, filter); + } else { + // only run this branch on updates, no at initial renders + setListener((prevListener) => { + bundleContext.removeServiceListener(prevListener); - const newListener = createListener(); + const newListener = createListener(); - setListener(newListener); + bundleContext.addServiceListener(newListener, filter); - bundleContext.addServiceListener(newListener, filter); + return newListener; + }); - setTracker({ - service: getService(filter), - }); + setTracker({ + service: getService(filter), + }); + } }, [filter]); return tracker;