Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More

cheap-di-react

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

cheap-di-react - npm Package Compare versions

Comparing version 3.3.1 to 4.0.0

@@ -1,2 +0,2 @@

export * from './useContainer';
export * from './useDiContext';
export * from './use';
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const tslib_1 = require("tslib");
tslib_1.__exportStar(require("./useContainer"), exports);
tslib_1.__exportStar(require("./useDiContext"), exports);
tslib_1.__exportStar(require("./use"), exports);
//# sourceMappingURL=index.js.map
export * from './DiContext';
export * from './decorators';
export * from './Providers';
export * from './hooks/use';
export * from './hooks';

@@ -5,5 +5,4 @@ "use strict";

tslib_1.__exportStar(require("./DiContext"), exports);
tslib_1.__exportStar(require("./decorators"), exports);
tslib_1.__exportStar(require("./Providers"), exports);
tslib_1.__exportStar(require("./hooks/use"), exports);
tslib_1.__exportStar(require("./hooks"), exports);
//# sourceMappingURL=index.js.map

@@ -1,2 +0,2 @@

import { DependencyRegistrator, ImplementationType } from 'cheap-di';
import { Container, DependencyRegistrator, ImplementationType } from 'cheap-di';
import { FC, ReactNode } from 'react';

@@ -8,2 +8,3 @@ declare type Dependency = (dependencyRegistrator: DependencyRegistrator) => void;

self?: SelfDependency[];
parentContainer?: Container;
/** if it is provided, logging will be enabled */

@@ -10,0 +11,0 @@ debugName?: string;

@@ -7,14 +7,12 @@ "use strict";

const react_1 = require("react");
const decorators_1 = require("../decorators");
const DiContext_1 = require("../DiContext");
const hooks_1 = require("../hooks");
const configureStateful_1 = require("../hooks/configureStateful");
const utils_1 = require("../utils");
const DIProvider = props => {
const { dependencies, self, debugName, children, } = props;
const { dependencies, self, parentContainer, debugName, children, } = props;
const [logger] = (0, react_1.useState)(() => new utils_1.InternalLogger(debugName));
const [initialized, setInitialized] = (0, react_1.useState)(false);
const timerRef = (0, react_1.useRef)(null);
const [contextValue, rerender] = (0, hooks_1.useContainer)(logger);
const container = contextValue.container;
const diContext = (0, hooks_1.useDiContext)({ logger, parentContainer });
const container = diContext.container;
(0, react_1.useEffect)(() => {

@@ -38,12 +36,5 @@ var _a;

logger.log('singleton', constructor, 'founded');
const instance = container.resolve(type);
(0, configureStateful_1.configureStateful)(instance, container.rootContainer.rerender, logger);
// resolve type to get and register its instance
container.resolve(type);
}
if ((0, decorators_1.isStateful)(constructor)) {
logger.log('stateful', constructor, 'founded');
container.skipParentInstanceResolvingOnce(); // target instance should be instantiated from zero
const instance = container.resolve(type);
container.registerInstance(instance).as(type);
(0, configureStateful_1.configureStateful)(instance, rerender, logger);
}
}

@@ -69,3 +60,3 @@ if (container.parentContainer && singletonsSizeBeforeDependenciesUpdate !== container.getSingletons().size) {

}
return ((0, jsx_runtime_1.jsx)(DiContext_1.DiContext.Provider, Object.assign({ value: contextValue }, { children: (0, jsx_runtime_1.jsx)(MemoizedChildren, { children: children }) })));
return ((0, jsx_runtime_1.jsx)(DiContext_1.DiContext.Provider, Object.assign({ value: diContext }, { children: (0, jsx_runtime_1.jsx)(MemoizedChildren, { children: children }) })));
};

@@ -72,0 +63,0 @@ const MemoizedChildren = (0, react_1.memo)(({ children }) => (0, jsx_runtime_1.jsx)(react_1.Fragment, { children: children }));

@@ -8,3 +8,2 @@ "use strict";

const cheap_di_1 = require("cheap-di");
const decorators_1 = require("../decorators");
const DIProvider_1 = require("./DIProvider");

@@ -142,52 +141,2 @@ const DIOneTimeProvider_1 = require("./DIOneTimeProvider");

}));
test('stateful', () => tslib_1.__awaiter(void 0, void 0, void 0, function* () {
let MyStateful = class MyStateful {
constructor() {
this.message = 'initial';
}
};
MyStateful = tslib_1.__decorate([
decorators_1.stateful
], MyStateful);
const dependencies = [
dr => dr.registerType(MyStateful),
];
const firstMessage = 'level 1';
const secondMessage = 'level 2';
const button1 = 'my-button-1';
const button2 = 'my-button-2';
const RootComponent = () => {
return ((0, jsx_runtime_1.jsxs)(DIProvider_1.DIProvider, Object.assign({ dependencies: dependencies }, { children: [(0, jsx_runtime_1.jsx)(LoadComponent, { message: firstMessage, buttonId: button1 }), (0, jsx_runtime_1.jsx)(ReadComponent, {}), (0, jsx_runtime_1.jsxs)(DIProvider_1.DIProvider, Object.assign({ dependencies: dependencies }, { children: [(0, jsx_runtime_1.jsx)(LoadComponent, { message: secondMessage, buttonId: button2 }), (0, jsx_runtime_1.jsx)(ReadComponent, {})] }))] })));
};
const LoadComponent = ({ message, buttonId }) => {
const myStateful = (0, hooks_1.use)(MyStateful);
return ((0, jsx_runtime_1.jsx)("div", { children: (0, jsx_runtime_1.jsx)("button", { "data-testid": buttonId, onClick: () => {
myStateful.message = message;
} }) }));
};
const ReadComponent = () => {
const myStateful = (0, hooks_1.use)(MyStateful);
return ((0, jsx_runtime_1.jsx)("span", { children: myStateful.message }));
};
const { queryAllByText, getByTestId, rerender } = (0, react_1.render)((0, jsx_runtime_1.jsx)(RootComponent, {}));
expect(queryAllByText('initial').length).toBe(2);
expect(queryAllByText(firstMessage).length).toBe(0);
expect(queryAllByText(secondMessage).length).toBe(0);
// first state
yield (0, react_1.act)(() => tslib_1.__awaiter(void 0, void 0, void 0, function* () {
react_1.fireEvent.click(getByTestId(button1));
}));
rerender((0, jsx_runtime_1.jsx)(RootComponent, {}));
expect(queryAllByText('initial').length).toBe(1);
expect(queryAllByText(firstMessage).length).toBe(1);
expect(queryAllByText(secondMessage).length).toBe(0);
// second state
yield (0, react_1.act)(() => tslib_1.__awaiter(void 0, void 0, void 0, function* () {
react_1.fireEvent.click(getByTestId(button2));
}));
rerender((0, jsx_runtime_1.jsx)(RootComponent, {}));
expect(queryAllByText('initial').length).toBe(0);
expect(queryAllByText(firstMessage).length).toBe(1);
expect(queryAllByText(secondMessage).length).toBe(1);
}));
test('nested singletons', () => tslib_1.__awaiter(void 0, void 0, void 0, function* () {

@@ -194,0 +143,0 @@ let Service1 = class Service1 {

@@ -1,2 +0,2 @@

import { AbstractConstructor, Constructor, ContainerImpl, ImplementationType, ImplementationTypeWithInjection, RegistrationType } from 'cheap-di';
import { AbstractConstructor, Constructor, ContainerImpl, ImplementationTypeWithInjection } from 'cheap-di';
export declare class ReactContainer extends ContainerImpl {

@@ -8,14 +8,5 @@ parentContainer?: ReactContainer | undefined;

constructor(parentContainer?: ReactContainer | undefined);
registerType<TInstance>(implementationType: ImplementationType<TInstance>): {
as: <TBase extends Partial<TInstance>>(type: RegistrationType<TBase>) => {
with: (...injectionParams: any[]) => void;
};
asSingleton: <TBase_1 extends Partial<TInstance>>(type?: RegistrationType<TBase_1> | undefined) => {
with: (...injectionParams: any[]) => void;
};
with: (...injectionParams: any[]) => void;
};
get rootContainer(): ReactContainer;
sameParent(parentContainer?: ContainerImpl): boolean;
getDependencies(): Map<RegistrationType<any>, Object | ImplementationTypeWithInjection<any>>;
getDependencies(): Map<import("cheap-di/dist/types").RegistrationType<any>, Object | ImplementationTypeWithInjection<any>>;
localScope<Callback extends (container: ReactContainer) => any>(callback: Callback): Callback extends (container: ReactContainer) => infer Result ? Result : void;

@@ -22,0 +13,0 @@ skipParentInstanceResolvingOnce(): void;

@@ -5,4 +5,2 @@ "use strict";

const cheap_di_1 = require("cheap-di");
const decorators_1 = require("./decorators");
const stateful_1 = require("./decorators/stateful");
class ReactContainer extends cheap_di_1.ContainerImpl {

@@ -16,14 +14,2 @@ constructor(parentContainer) {

}
registerType(implementationType) {
if (!(0, decorators_1.isStateful)(implementationType)) {
(0, decorators_1.stateful)(implementationType);
}
const registration = super.registerType(implementationType);
const superAsSingleton = registration.asSingleton;
registration.asSingleton = (type) => {
(0, stateful_1.removeStateful)(implementationType);
return superAsSingleton(type);
};
return registration;
}
get rootContainer() {

@@ -30,0 +16,0 @@ return this.findRootContainer();

export * from './InternalLogger';
export * from './reconfigureObject';

@@ -5,3 +5,2 @@ "use strict";

tslib_1.__exportStar(require("./InternalLogger"), exports);
tslib_1.__exportStar(require("./reconfigureObject"), exports);
//# sourceMappingURL=index.js.map
{
"name": "cheap-di-react",
"version": "3.3.1",
"version": "4.0.0",
"description": "",

@@ -14,4 +14,7 @@ "scripts": {

"@types/react": "18.0.12",
"cheap-di": "3.4.0",
"jest": "28.1.1",
"jest-environment-jsdom": "28.1.1",
"react": "17.0.2",
"react-dom": "17.0.2",
"ts-jest": "28.0.5",

@@ -22,5 +25,5 @@ "tslib": "2.4.0",

"peerDependencies": {
"cheap-di": ">= 3.3.1",
"react": ">= 16.14.0",
"react-dom": ">= 16.14.0"
"cheap-di": ">= 3.4.0",
"react": ">= 17.0.2",
"react-dom": ">= 17.0.2"
},

@@ -27,0 +30,0 @@ "files": [

@@ -35,4 +35,4 @@ # cheap-di-react

import {
Provider,
OneTimeProvider,
DIProvider,
DIOneTimeProvider,
} from 'cheap-di-react';

@@ -44,3 +44,3 @@ import { Logger, ConsoleLogger } from './logger';

<>
<Provider
<DIProvider
// will update dependencies on each render

@@ -54,5 +54,5 @@ dependencies={[

<ComponentA/>
</Provider>
</DIProvider>
<OneTimeProvider
<DIOneTimeProvider
// will use initial dependecies (it uses useMemo under hood)

@@ -66,3 +66,3 @@ dependencies={[

<ComponentA/>
</OneTimeProvider>
</DIOneTimeProvider>
</>

@@ -87,141 +87,4 @@ );

If you mark your service as `@stateful` (or `@singleton`), Provider will create instance of the service and configures
it fields (with Object.defineProperties), those fields changes (<b>reassign</b>) will trigger `Provider` rerender throw
`React.Context`, and service consumers will receive field update.
Difference between `@singleton` and `@stateful` that for `@singleton` there will be created only one instance for entire
Provider tree, and for `@stateful` there will be created different instance per each Provider that register this type.
`stateful`
```tsx
import { OneTimeProvider, use, stateful } from 'cheap-di-react';
@stateful
class MyStateful {
message: string = 'initial';
}
const RootComponent = () => {
return (
<OneTimeProvider self={[MyStateful]}>
<LoadComponent message="level 1"/>
<ReadComponent/>
<OneTimeProvider self={[MyStateful]}>
<LoadComponent message="level 2"/>
<ReadComponent/>
</OneTimeProvider>
</OneTimeProvider>
);
};
const LoadComponent = ({ message }: { message: string }) => {
const myStateful = use(MyStateful);
return (
<button onClick={() => { myStateful.message = message; }}/>
);
};
const ReadComponent = () => {
const myStateful = use(MyStateful);
return (
<span>
{myStateful.message}
</span>
);
};
```
`singleton`
```tsx
import { singleton } from 'cheap-di';
import { OneTimeProvider, use } from 'cheap-di-react';
@singleton
class MySingleton {
data: string[] = ['initial'];
async loadData() {
this.data = await Promise.resolve(['some']);
}
}
const RootComponent = () => {
return (
<OneTimeProvider self={[MySingleton]}>
<Component/>
</OneTimeProvider>
);
};
const Component = () => {
const mySingleton = use(MySingleton);
useEffect(() => {
(async () => {
await mySingleton.loadData();
})();
}, []);
return (
<div>
{mySingleton.data.map(text => (
<span key={text} style={{ color: 'blue' }}>
{text}
</span>
))}
</div>
);
};
```
You can configure your services with more classic-way - when your class know nothing about how and where it will be
used.
`stateful`
```tsx
import { OneTimeProvider, use } from 'cheap-di-react';
class MyStateful {
message: string = 'initial';
}
const RootComponent = () => {
return (
<OneTimeProvider dependencies={[ dr => dr.registerType(MyStateful) ]}>
<LoadComponent message="level 1"/>
<ReadComponent/>
<OneTimeProvider dependencies={[ dr => dr.registerType(MyStateful) ]}>
<LoadComponent message="level 2"/>
<ReadComponent/>
</OneTimeProvider>
</OneTimeProvider>
);
};
```
`singleton`
```tsx
import { OneTimeProvider, use } from 'cheap-di-react';
class MySingleton {
data: string[] = ['initial'];
async loadData() {
this.data = await Promise.resolve(['some']);
}
}
const RootComponent = () => {
return (
<OneTimeProvider dependencies={[ dr => dr.registerType(MySingleton).asSingleton() ]}>
<Component/>
</OneTimeProvider>
);
};
```
But remember, if you want to use auto resolving your dependencies with typescript reflection, you need
`"emitDecoratorMetadata": true,` in `tsconfig.ts` and any class-decorator for your service-class (read more in
`cheap-di` README.md)

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet