diff --git a/CHANGELOG.md b/CHANGELOG.md
index 04cee30..aa04c90 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,9 @@
+# 1.3.0
+
+- Fix doc typo
+- Add `ctor` param for `ProviderProps`
+- Separate `ProviderProps` to disallow using `cleanUp` when use it with `source: T`
+
# 1.2.0
- Cleanup function of `Provider` only called for `create` source.
diff --git a/README.md b/README.md
index 9d3982c..c0ac090 100644
--- a/README.md
+++ b/README.md
@@ -54,7 +54,7 @@ Expose a persisted instance between renders. This value will be kept with `useRe
,
```
-These 2 two types only should be used one at a time for each `Provider` and kept it that way throughout the component's lifeCycle. Use them interchangably may cause unexpected behavior.
+These 2 two types only should be used one at a time for each `Provider` and kept it that way throughout the component's lifeCycle. Use them interchangeably may cause unexpected behavior.
#### Named Provider
@@ -90,6 +90,24 @@ const data: CustomType = {value: "text"};
This mechanism is important for retrieving the value later on, especially when dealing with complex type systems in TypeScript.
+#### Abstract Provider
+
+For class instance, `Provider` will automatically infer name of the type based on provided value. But in architecture point of view, there are times we would need to hide the type of implementation and expose abstraction superclass only.
+To do this, we can use the `ctor` parameter in `Provider`
+
+You can do the same with the `name` parameter too. Infact, all of this behavior will be overwritten by the `name` parameter when specified.
+
+```tsx
+class SuperClass {}
+
+class SubClass extends SuperClasss {}
+
+// map query key will be 'SuperClass'
+
+
+,
+```
+
#### Scoped data overwrite
Be warned that providing duplicated `name` values for data may lead to overwrite behavior. If multiple instances of `Provider` use the same name for their data, the previous provided value with the same name will be replaced by the subsequent one.
diff --git a/package.json b/package.json
index 619ecc9..89282c6 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "react-scoped-provider",
- "version": "1.2.0",
+ "version": "1.3.0",
"description": "Library for DI in react without the need of self-creating context everytime.",
"type": "module",
"source": "src/index.ts",
diff --git a/src/Provider/index.tsx b/src/Provider/index.tsx
index d3fd919..42360a2 100644
--- a/src/Provider/index.tsx
+++ b/src/Provider/index.tsx
@@ -1,14 +1,29 @@
-import { PropsWithChildren, useEffect, useRef } from 'react'
+import { ReactNode, useEffect, useRef } from 'react'
import { Create } from '../types'
-import { isCreate } from '../utils'
+import { getObjectRuntimeName, isCreate } from '../utils'
import { ProviderScope } from '../ProviderScope'
-type ProviderProps = {
+interface ProviderProps {
source: Create | T
cleanUp?: (data: T) => void
name?: string
+ children?: ReactNode
+ ctor?: new (...a: any) => any
}
-function Provider({ source, cleanUp, children, name }: PropsWithChildren>): JSX.Element {
+
+interface CreateProviderProps extends ProviderProps {
+ source: Create
+ ctor?: new (...a: any) => T
+}
+interface ValueProviderProps extends ProviderProps {
+ source: T
+ cleanUp?: undefined
+ ctor?: new (...a: any) => T
+}
+
+function Provider(props: ValueProviderProps): JSX.Element
+function Provider(props: CreateProviderProps): JSX.Element
+function Provider({ source, cleanUp, children, name, ctor }: ProviderProps): JSX.Element {
const createdData = useRef(isCreate(source) ? source() : undefined)
const valueData: T | undefined = isCreate(source) ? undefined : source
useEffect(() => {
@@ -22,11 +37,14 @@ function Provider({ source, cleanUp, children, name }: PropsWithChildren
+
{children}
)
}
-export type { ProviderProps }
+export type { ProviderProps, CreateProviderProps, ValueProviderProps }
export { Provider }
diff --git a/src/index.ts b/src/index.ts
index 539eee9..cd7f0bc 100644
--- a/src/index.ts
+++ b/src/index.ts
@@ -9,7 +9,7 @@ import {
UseProviderConfigsDisAllowUndef,
UseProviderConfigs,
} from './hooks'
-import { Provider, ProviderProps } from './Provider'
+import { Provider, ProviderProps, CreateProviderProps, ValueProviderProps } from './Provider'
import { ContextData, ProviderContext } from './ProviderContext'
import { ProviderScope, ProviderScopeProps } from './ProviderScope'
import { ResourcesNotProvidedError } from './errors'
@@ -42,7 +42,7 @@ export type {
NamedConsumerAllowUndefProps,
}
export { Create }
-export { ProviderProps, Provider }
+export { ProviderProps, Provider, CreateProviderProps, ValueProviderProps }
export { ProviderScope, ProviderScopeProps }
export { ProviderContext, ContextData }
export {
diff --git a/test/Provider/cleanup.test.tsx b/test/Provider/cleanup.test.tsx
index 18b15fe..413d303 100644
--- a/test/Provider/cleanup.test.tsx
+++ b/test/Provider/cleanup.test.tsx
@@ -1,24 +1,13 @@
import { render } from '@testing-library/react'
import { Provider } from '../../src'
-it('cleanup provided value', () => {
- const cleanUpFunc = jest.fn((value) => value)
- const { unmount } = render(
-
-
- ,
- )
- unmount()
- expect(cleanUpFunc.mock.calls).toHaveLength(0)
-})
-
class A {}
it('cleanup provided Create', () => {
const instance = new A()
const cleanUpFunc = jest.fn((value) => value)
const { unmount } = render(
- instance} cleanUp={(value) => cleanUpFunc(value)}>
+ instance} cleanUp={(data) => cleanUpFunc(data)}>
,
)
diff --git a/test/Provider/render.test.tsx b/test/Provider/render.test.tsx
index 4db57f7..2834ebe 100644
--- a/test/Provider/render.test.tsx
+++ b/test/Provider/render.test.tsx
@@ -51,3 +51,60 @@ it('render name provided create without error', () => {
const expectedText = 'Rendered'
expect(renderedText).toBe(expectedText)
})
+
+it('render String ctor without error', () => {
+ const { container } = render(
+
+
+ ,
+ )
+ const rendered = getByTestId(container, 'text')
+ const renderedText = rendered.textContent
+ const expectedText = 'Rendered'
+ expect(renderedText).toBe(expectedText)
+})
+
+it('render Boolean ctor without error', () => {
+ const { container } = render(
+ true} name='value'>
+
+ ,
+ )
+ const rendered = getByTestId(container, 'text')
+ const renderedText = rendered.textContent
+ const expectedText = 'Rendered'
+ expect(renderedText).toBe(expectedText)
+})
+
+it('render Number ctor without error', () => {
+ const { container } = render(
+
+
+ ,
+ )
+ const rendered = getByTestId(container, 'text')
+ const renderedText = rendered.textContent
+ const expectedText = 'Rendered'
+ expect(renderedText).toBe(expectedText)
+})
+
+it('render Custom ctor without error', () => {
+ const { container } = render(
+
+
+ ,
+ )
+ const rendered = getByTestId(container, 'text')
+ const renderedText = rendered.textContent
+ const expectedText = 'Rendered'
+ expect(renderedText).toBe(expectedText)
+})
+
+class A {
+ count: number
+ constructor(count: number) {
+ this.count = count
+ }
+}
+
+class B extends A {}
diff --git a/test/Provider/typeNameRespected.test.tsx b/test/Provider/typeNameRespected.test.tsx
new file mode 100644
index 0000000..91acd01
--- /dev/null
+++ b/test/Provider/typeNameRespected.test.tsx
@@ -0,0 +1,58 @@
+import { getByTestId, render } from '@testing-library/react'
+import { Provider, useNamedProvider } from '../../src'
+
+const DisplayRendered = ({ name }: { name: string }) => {
+ useNamedProvider(name)
+ return Rendered
+}
+
+class SuperClass {
+ count: number
+ constructor(count: number) {
+ this.count = count
+ }
+}
+
+class SubClass extends SuperClass {
+ count2: number
+ constructor(count2: number) {
+ super(0)
+ this.count2 = count2
+ }
+}
+
+it('respect Subclass type', () => {
+ const { container } = render(
+
+
+ ,
+ )
+ const rendered = getByTestId(container, 'text')
+ const renderedText = rendered.textContent
+ const expectedText = 'Rendered'
+ expect(renderedText).toBe(expectedText)
+})
+
+it('respect Superclass ctor type', () => {
+ const { container } = render(
+
+
+ ,
+ )
+ const rendered = getByTestId(container, 'text')
+ const renderedText = rendered.textContent
+ const expectedText = 'Rendered'
+ expect(renderedText).toBe(expectedText)
+})
+
+it('respect specified name', () => {
+ const { container } = render(
+
+
+ ,
+ )
+ const rendered = getByTestId(container, 'text')
+ const renderedText = rendered.textContent
+ const expectedText = 'Rendered'
+ expect(renderedText).toBe(expectedText)
+})