@adimm/x-injection-reactjs 0.3.1 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,7 +1,7 @@
1
1
  <h1 align="center">
2
2
  xInjection ReactJS <a href="https://www.npmjs.com/package/@adimm/x-injection-reactjs" target="__blank"><img src="https://badgen.net/npm/v/@adimm/x-injection-reactjs"></a>
3
- <img src="https://badgen.net/npm/license/@adimm/x-injection-reactjs">
4
3
  <a href="https://app.codecov.io/gh/AdiMarianMutu/x-injection-reactjs" target="__blank"><img src="https://badgen.net/codecov/c/github/AdiMarianMutu/x-injection-reactjs"></a>
4
+ <img src="https://badgen.net/npm/license/@adimm/x-injection-reactjs">
5
5
  </h1>
6
6
 
7
7
  <p align="center">
@@ -19,24 +19,32 @@ xInjection ReactJS <a href="https://www.npmjs.com/package/@adimm/x-injection-rea
19
19
  - [Installation](#installation)
20
20
  - [TypeScript Configuration](#typescript-configuration)
21
21
  - [Getting Started](#getting-started)
22
- - [Component ProviderModules](#component-providermodules)
23
- - [Component Injection](#component-injection)
24
- - [Via anonymous function](#via-anonymous-function)
25
- - [Via named function](#via-named-function)
22
+ - [Quick Start](#quick-start)
23
+ - [Conventions](#conventions)
24
+ - [Component Module](#component-module)
25
+ - [Component Service](#component-service)
26
+ - [How to tie a `ProviderModule` to a `Component`?](#how-to-tie-a-providermodule-to-a-component)
27
+ - [Is your component re-usable?](#is-your-component-re-usable)
28
+ - [Yes](#yes)
29
+ - [No](#no)
30
+ - [How to control a Child component providers from Parent component?](#how-to-control-a-child-component-providers-from-parent-component)
31
+ - [Override the entire Child Module](#override-the-entire-child-module)
32
+ - [Override only specific Child Providers](#override-only-specific-child-providers)
26
33
  - [Hook Injection](#hook-injection)
27
34
  - [Examples](#examples)
28
35
  - [Composable components](#composable-components)
29
36
  - [Unit Tests](#unit-tests)
30
37
  - [Documentation](#documentation)
31
38
  - [Contributing](#contributing)
39
+ - [Credits](#credits)
32
40
 
33
41
  ## Overview
34
42
 
35
- **xInjection** is a robust Inversion of Control [(IoC)](https://en.wikipedia.org/wiki/Inversion_of_control) library that extends [InversifyJS](https://github.com/inversify/InversifyJS) with a modular, [NestJS](https://github.com/nestjs/nest)-inspired Dependency Injection [(DI)](https://en.wikipedia.org/wiki/Dependency_injection) system. It enables you to **encapsulate** dependencies with fine-grained control using **[ProviderModule](https://adimarianmutu.github.io/x-injection/classes/ProviderModule.html)** classes, allowing for clean **separation** of concerns and **scalable** architecture.
36
-
37
- Each `ProviderModule` manages its _own_ container, supporting easy **decoupling** and _explicit_ control over which providers are **exported** and **imported** across modules. The global **[AppModule](https://adimarianmutu.github.io/x-injection/variables/AppModule.html)** is always available, ensuring a seamless foundation for your application's DI needs.
43
+ This is the _official_ [ReactJS](https://react.dev/) implementation of the [xInjection](https://github.com/AdiMarianMutu/x-injection) library.
38
44
 
39
- > For more details and info please access the [xInjection](https://github.com/AdiMarianMutu/x-injection) library repository.
45
+ > [!Warning]
46
+ >
47
+ > The usage of the `base` library will not be explained here, I'll assume you already know how to use the `xInjection` library, if that's not the case, please refer to the `xInjection` [Gettng Started](https://github.com/AdiMarianMutu/x-injection?tab=readme-ov-file#getting-started) section.
40
48
 
41
49
  ## Installation
42
50
 
@@ -52,6 +60,8 @@ Then install `xInjection` for React:
52
60
  npm i @adimm/x-injection-reactjs
53
61
  ```
54
62
 
63
+ > [!Note]
64
+ >
55
65
  > You may also have to install the parent library via `npm i @adimm/x-injection`
56
66
 
57
67
  ### TypeScript Configuration
@@ -69,126 +79,192 @@ Add the following options to your `tsconfig.json` to enable decorator metadata:
69
79
 
70
80
  ## Getting Started
71
81
 
72
- If you never used the parent library (`xInjection`), then please access the official [xInjection Repository](https://github.com/AdiMarianMutu/x-injection?tab=readme-ov-file#getting-started) to better understand how to use its `ReactJS` implementation.
82
+ ### Quick Start
73
83
 
74
- ### Component ProviderModules
84
+ ```tsx
85
+ const UserDashboardModuleBp = ProviderModule.blueprint({
86
+ id: 'ComponentUserDashboardModule',
87
+ imports: [UserModule],
88
+ exports: [UserModule],
89
+ });
75
90
 
76
- A [ComponentProviderModule](https://adimarianmutu.github.io/x-injection-reactjs/interfaces/IComponentProviderModule.html) isn't so different than the original [ProviderModule](https://adimarianmutu.github.io/x-injection/interfaces/IProviderModule.html) from the base `xInjection` library, the main difference being that it'll automatically create a [clone](https://adimarianmutu.github.io/x-injection-reactjs/interfaces/IComponentProviderModule.html#clone) of itself whenever a component is `mounted` and during the `unmount` process it'll [dispose](https://adimarianmutu.github.io/x-injection-reactjs/interfaces/IComponentProviderModule.html#dispose) itself.
91
+ const UserDashboard = provideModuleToComponent(UserDashboardModuleBp, () => {
92
+ const userService = useInject(UserService);
77
93
 
78
- This is needed so:
94
+ return (
95
+ <h1>
96
+ Hello {userService.firstName} {userService.lastName}!
97
+ </h1>
98
+ );
99
+ });
79
100
 
80
- - Each instance of a component has its own instance of the `ProviderModule` _(also known as `ContextualizedModule`)_
81
- - Whenever a component is unmounted, the container of that `ContextualizedModule` is destroyed, making sure that the resources can be garbage-collected by the JS garbage collector.
101
+ const App = () => {
102
+ return (
103
+ <>
104
+ <Navbar />
105
+ <UserDashboard />
106
+ <Footer />
107
+ </>
108
+ );
109
+ };
110
+ ```
111
+
112
+ ### Conventions
82
113
 
83
- > **Note:** By default each `ContextualizedModule` has its `InjectionScope` set to `Singleton`, you can of course change it by providing the [defaultScope](https://adimarianmutu.github.io/x-injection/interfaces/ProviderModuleOptions.html#defaultscope) property.
114
+ Before continuing you should read also the [Conventions](https://github.com/AdiMarianMutu/x-injection?tab=readme-ov-file#conventions) section of the _parent_ library.
84
115
 
85
- ### Component Injection
116
+ ### Component Module
86
117
 
87
- In order to be able to inject dependencies into your components, you must first supply them with a `ComponentProviderModule`.
118
+ You should create a separate file which you'll use to declare the `blueprint` of the _component_ `module`:
88
119
 
89
- This is how you can create one:
120
+ `user-dashboard/user-dashboard.module.ts`
90
121
 
91
122
  ```ts
92
- @Injectable()
93
- export class UserService {
94
- firstName: string;
95
- lastName: string;
123
+ export const UserDashboardModuleBp = ProviderModule.blueprint({
124
+ id: 'ComponentUserDashboardModule',
125
+ ...
126
+ });
127
+ ```
96
128
 
97
- generateFullName(): string {
98
- return `${firstName} ${lastName}`;
99
- }
100
- }
129
+ > [!Note]
130
+ >
131
+ > You should also prefix the `id` of the `blueprints` with `Component` as this will help you to debug your app much more easier when something goes wrong.
101
132
 
102
- export const UserComponentModule = new ComponentProviderModule({
103
- identifier: Symbol('UserComponentModule'),
104
- providers: [UserService],
105
- });
133
+ ### Component Service
134
+
135
+ You should create a separate file which you'll use to declare the _(main)_ `service` of the _component_.
106
136
 
107
- interface UserInfoProps {
137
+ `user-dashboard/user-dashboard.service.ts`
138
+
139
+ ```ts
140
+ @Injectable()
141
+ export class UserDashboardService {
108
142
  firstName: string;
109
143
  lastName: string;
110
144
  }
111
145
  ```
112
146
 
113
- Now you have to actually provide the `UserComponentModule` to your component(s). You can do so with 2 different methods:
147
+ ### How to tie a `ProviderModule` to a `Component`?
148
+
149
+ You first have to either create a `module` or `blueprint`, most of the times you'll use the `blueprint` option, if you are asking yourself how you should decide:
150
+
151
+ #### Is your component re-usable?
152
+
153
+ > Will you have **more** than **one** instance of that component?
114
154
 
115
- #### Via anonymous function
155
+ ##### Yes
116
156
 
117
- If you prefer to use the `const Component = () => {}` syntax, then you must use the [provideModuleToComponent](https://adimarianmutu.github.io/x-injection-reactjs/functions/provideModuleToComponent.html) method as shown below:
157
+ - Then you have to use a `blueprint`, the reason can be understood by reading [this](https://github.com/AdiMarianMutu/x-injection?tab=readme-ov-file#import-behavior).
118
158
 
119
- > **Note:** _This is the preferred method as it allows you to avoid wrapping your component within another provider once created._
159
+ ##### No
160
+
161
+ - Then you have to use a raw `module`, the reason is the opposite of the `blueprint` motive.
162
+
163
+ > [!Tip] If the above explaination is clear, please skip to the next section, otherwise keep reading.
164
+
165
+ Imagine that we have a `Button` component, clearly we'll have more than one instance of that component, this means that **each** _instance_ of the `Button` component must have its own `module`, where all the `singletons` will act as singletons _only inside_ the component **instance**.
166
+
167
+ > Therefore we leverage the `blueprint` _import_ behavior to achieve that naturally without additional overhead.
168
+
169
+ ---
170
+
171
+ After you created the `component module`, you can provide it to the actual component by using the [provideModuleToComponent](https://adimarianmutu.github.io/x-injection-reactjs/functions/provideModuleToComponent.html) _([HoC](https://legacy.reactjs.org/docs/higher-order-components.html))_ `method`.
120
172
 
121
173
  ```tsx
122
- // The UserInfo component will correctly infer the interface of `UserInfoProps` automatically!
123
- export const UserInfo = provideModuleToComponent<UserInfoProps>(UserComponentModule, ({ firstName, lastName }) => {
124
- const userService = useInject(UserService);
174
+ const UserDashboard = provideModuleToComponent(UserDashboardModuleBp, (props: UserDashboardProps) => {
175
+ ...
176
+ });
177
+ ```
178
+
179
+ ### How to control a Child component providers from Parent component?
180
+
181
+ If you need this design pattern, it is very easy to implement with `xInjection`, you actually have 2 options:
125
182
 
126
- userService.firstName = firstName;
127
- userService.lastName = lastName;
183
+ #### Override the entire Child Module
128
184
 
129
- return <p>Hello {userService.generateFullName()}!</p>;
185
+ Let's say that the `Child` component has this `module`:
186
+
187
+ ```ts
188
+ const ChildModuleBp = ProviderModule.blueprint({
189
+ id: 'ComponentChildModule',
190
+ providers: [ChildService],
191
+ exports: [ChildService],
130
192
  });
193
+ ```
131
194
 
132
- function MyApp() {
133
- return <UserInfo firstName="John" lastName="Doe" />;
134
- // Result
135
- //
136
- // <p>Hello John Doe!</p>
137
- }
195
+ What you can now do is to provide the `ChildService` from the `Parent` component, like this:
196
+
197
+ ```ts
198
+ const ParentModuleBp = ProviderModule.blueprint({
199
+ id: 'ComponentParentModule',
200
+ providers: [ParentService, ChildService],
201
+ exports: [ParentService, ChildService],
202
+ });
138
203
  ```
139
204
 
140
- #### Via named function
205
+ Then, when you are rendering the `Child` component from **within** the `Parent` component:
141
206
 
142
- Or if you prefer to use the `function Component() {}` syntax, then you must use the [ProvideModule](https://adimarianmutu.github.io/x-injection-reactjs/functions/ProvideModule.html) `HoC` as shown below:
207
+ ```ts
208
+ const ParentComponent = provideModuleToComponent(ParentModuleBp, ({ module }) => {
209
+ // the `module` prop is always available and automatically injected into the `props` object.
143
210
 
144
- > **Note:** _If you need to access the contextualized `module` forwarded to your component, you can wrap the component props with the [PropsWithModule](https://adimarianmutu.github.io/x-injection-reactjs/types/PropsWithModule.html) generic type._
211
+ return <ChildComponent module={module} />;
212
+ });
213
+ ```
145
214
 
146
- ```tsx
147
- export function UserInfo({ firstName, lastName }: UserInfoProps) {
148
- const userService = useInject(UserService);
215
+ Now the `ChildComponent` will be instantiated with the `module` received from the `ParentComponent`, therefore it'll use the `ChildService` managed into the `ParentModule`.
149
216
 
150
- userService.firstName = firstName;
151
- userService.lastName = lastName;
217
+ > [!Tip]
218
+ >
219
+ > This is perfect to use when you are writing _unit tests_ and you want to mock an entire component `module`
152
220
 
153
- return <p>Hello {userService.generateFullName()}!</p>;
154
- }
221
+ #### Override only specific Child Providers
155
222
 
156
- function MyApp() {
157
- return (
158
- <ProvideModule module={UserComponentModule}>
159
- <UserInfo firstName="John" lastName="Doe" />
160
- </ProvideModule>
161
- );
162
- // Result
163
- //
164
- // <p>Hello John Doe!</p>
165
- }
223
+ > This is the approach which you should strive to use most of the times as it is less prone to _"human error"_ than overriding the entire module.
224
+
225
+ Let's re-use the same example as the one from the above, the `ParentModule`:
226
+
227
+ ```ts
228
+ const ParentModuleBp = ProviderModule.blueprint({
229
+ id: 'ComponentParentModule',
230
+ providers: [ParentService, ChildService],
231
+ exports: [ParentService, ChildService],
232
+ });
166
233
  ```
167
234
 
168
- That's all you need to do, at least for simple components 😃.
235
+ And now the rendering part:
169
236
 
170
- > You can find more complex examples at the [Examples](#examples) section.
237
+ ```ts
238
+ const ParentComponent = provideModuleToComponent(ParentModuleBp, () => {
239
+ // notice that we are not using the `module` prop anymore.
240
+ const childService = useInject(ChildService);
171
241
 
172
- ### Hook Injection
242
+ return <ChildComponent inject={[{ provide: ChildService, useValue: childService }]} />;
243
+ });
244
+ ```
173
245
 
174
- You already have seen in action the low-level [useInject](https://adimarianmutu.github.io/x-injection-reactjs/functions/useInject.html) hook _(take a look also at the [useInjectMany](https://adimarianmutu.github.io/x-injection-reactjs/functions/useInjectMany.html) hook)_. It is quite useful when you just have to inject quickly some dependencies into a component quite simple.
246
+ By using the `inject` prop _(which as the `module` prop is always available)_ you'll _"swap"_ the `ChildService` provider with a [ProviderValueToken](https://adimarianmutu.github.io/x-injection/types/ProviderValueToken.html) which provides the `ChildService` **instance** instantiated by the `ParentComponent`.
175
247
 
176
- What it does under the hood? Finds the nearest contextualized module and resolves from it the required dependencies into your component, that's all.
248
+ > [!Note]
249
+ >
250
+ > If you are asking yourself `Why would I want to do that?`, that's a valid question, and most of the times you'll **not** need this feature, but sometimes, when you _compose_ components, being able to control the _providers_ of the children components becomes very useful. Check the [Composable Components](#composable-components) example to understand.
177
251
 
178
- But, as your UI will grow, you'll soon discover that you may inject more dependencies into a component, or even in multiple components, therefore you'll end up writing a lot of duplicated code, well, as per the [DRY](https://en.wikipedia.org/wiki/Don%27t_repeat_yourself#:~:text=%22Don't%20repeat%20yourself%22,redundancy%20in%20the%20first%20place.) principle, that's not good! 🥲
252
+ ### Hook Injection
253
+
254
+ You already have seen in action the low-level [useInject](https://adimarianmutu.github.io/x-injection-reactjs/functions/useInject.html) hook _(take a look also at the [useInjectMany](https://adimarianmutu.github.io/x-injection-reactjs/functions/useInjectMany.html) hook)_. It is quite useful when you just have to inject quickly some dependencies into a component quite simple.
179
255
 
180
- This means that we can actually use the [hookFactory](https://adimarianmutu.github.io/x-injection-reactjs/functions/hookFactory.html) method to compose a _custom_ hook with access to any dependency available in the component contextualized module.
256
+ But, as your UI will _grow_, you'll soon discover that you may inject _more_ dependencies into a component, or even in multiple components, therefore you'll end up writing a lot of duplicated code, well, as per the [DRY](https://en.wikipedia.org/wiki/Don%27t_repeat_yourself#:~:text=%22Don't%20repeat%20yourself%22,redundancy%20in%20the%20first%20place.) principle, we want to _avoid_ that.
181
257
 
182
- Having the above examples with the `UserService`, we'll create a custom `generateFullName` hook.
258
+ This means that we can actually use the [hookFactory](https://adimarianmutu.github.io/x-injection-reactjs/functions/hookFactory.html) method to compose a _custom_ hook with access to any dependency available in the component module.
183
259
 
184
260
  ```ts
185
261
  // The `HookWithDeps` generic type will help
186
262
  // in making sure that the `useGenerateUserFullName` hooks params are correctly visible.
187
263
  // The 1st generic param must be the hook params (Like `UserInfoProps`)
188
- // and starting from the 2nd generic param you must provide the type of your dependencies.
264
+ // and the 2nd generic param must be an `array` with the providers type.
189
265
  const useGenerateUserFullName = hookFactory({
190
266
  // The `use` property is where you write your hook implementation.
191
- use: ({ firstName, lastName, deps: [userService] }: HookWithDeps<UserInfoProps, UserService>) => {
267
+ use: ({ firstName, lastName, deps: [userService] }: HookWithDeps<UserInfoProps, [UserService]>) => {
192
268
  userService.firstName = firstName;
193
269
  userService.lastName = lastName;
194
270
 
@@ -202,7 +278,7 @@ const useGenerateUserFullName = hookFactory({
202
278
  });
203
279
  ```
204
280
 
205
- Now you can use it in inside any component which has access to a contextualized module which can provide the `UserService`.
281
+ Now you can use it in inside any component which is using a `module` which can provide the `UserService`.
206
282
 
207
283
  ```tsx
208
284
  export function UserInfo({ firstName, lastName }: UserInfoProps) {
@@ -212,6 +288,10 @@ export function UserInfo({ firstName, lastName }: UserInfoProps) {
212
288
  }
213
289
  ```
214
290
 
291
+ > **Note:** _If your custom hook does not accept any parameter, you can provide `void` to the 1st generic type._
292
+ >
293
+ > e.g: `use: ({ deps: [userService] }: HookWithDeps<void, [UserService]>)`
294
+
215
295
  ## Examples
216
296
 
217
297
  ### Composable components
@@ -249,8 +329,8 @@ export class InputboxService {
249
329
  }
250
330
  }
251
331
 
252
- export const InputboxModule = new ComponentProviderModule({
253
- identifier: Symbol('InputboxModule'),
332
+ export const InputboxModuleBp = ProviderModule.blueprint({
333
+ id: 'ComponentInputboxModule',
254
334
  provides: [InputboxService],
255
335
  exports: [InputboxService],
256
336
  });
@@ -263,7 +343,7 @@ export interface InputboxProps {
263
343
  initialValue: string;
264
344
  }
265
345
 
266
- export const Inputbox = provideModuleToComponent<InputboxProps>(InputboxModule, ({ initialValue }) => {
346
+ export const Inputbox = provideModuleToComponent<InputboxProps>(InputboxModuleBp, ({ initialValue }) => {
267
347
  const service = useInject(InputboxService);
268
348
  const [, setCurrentValue] = useState(initialValue);
269
349
  service.setStateValue = setCurrentValue;
@@ -290,8 +370,8 @@ export class ListviewService {
290
370
  /* Remaining fancy implementation */
291
371
  }
292
372
 
293
- export const ListviewModule = new ComponentProviderModule({
294
- identifier: Symbol('ListviewModule'),
373
+ export const ListviewModuleBp = ProviderModule.blueprint({
374
+ id: 'ComponentListviewModule',
295
375
  provides: [ListviewService],
296
376
  exports: [ListviewService],
297
377
  });
@@ -304,7 +384,7 @@ export interface ListviewProps {
304
384
  items: any[];
305
385
  }
306
386
 
307
- export const Listview = provideModuleToComponent<ListviewProps>(ListviewModule, ({ items }) => {
387
+ export const Listview = provideModuleToComponent<ListviewProps>(ListviewModuleBp, ({ items }) => {
308
388
  const service = useInject(ListviewService);
309
389
 
310
390
  /* Remaining fancy implementation */
@@ -338,15 +418,15 @@ export class DropdownService {
338
418
  /* Remaining fancy implementation */
339
419
  }
340
420
 
341
- export const DropdownModule = new ComponentProviderModule({
342
- identifier: Symbol('DropdownModule'),
421
+ export const DropdownModuleBp = ProviderModule.blueprint({
422
+ id: 'ComponentDropdownModule',
343
423
  // It is very important that we import all the exportable dependencies from the `ListviewModule`!
344
- imports: [ListviewModule],
424
+ imports: [ListviewModuleBp],
345
425
  provides: [DropdownService],
346
426
  exports: [
347
427
  // Let's also re-export the dependencies of the `ListviewModule` so once we import the `DropdownModule`
348
428
  // somewhere elese, we get access to the `ListviewModule` exported dependencies as well!
349
- ListviewModule,
429
+ ListviewModuleBp,
350
430
  // Let's not forget to also export our `DropdownService` :)
351
431
  DropdownService,
352
432
  ],
@@ -363,7 +443,7 @@ export interface DropdownProps {
363
443
  }
364
444
 
365
445
  export const Dropdown = provideModuleToComponent<DropdownProps>(
366
- ListviewModule,
446
+ ListviewModuleBp,
367
447
  ({ listviewProps, initialSelectedValue }) => {
368
448
  const service = useInject(DropdownService);
369
449
 
@@ -412,9 +492,9 @@ export class AutocompleteService {
412
492
  /* Remaining fancy implementation */
413
493
  }
414
494
 
415
- export const AutocompleteModule = new ComponentProviderModule({
416
- identifier: Symbol('AutocompleteModule'),
417
- imports: [InputboxModule, DropdownModule],
495
+ export const AutocompleteModuleBp = ProviderModule.blueprint({
496
+ id: 'ComponentAutocompleteModule',
497
+ imports: [InputboxModuleBp, DropdownModuleBp],
418
498
  provides: [AutocompleteService],
419
499
  // If we don't plan to share the internal dependencies of the
420
500
  // Autocomplete component, then we can omit the `exports` array declaration.
@@ -431,7 +511,7 @@ export interface AutocompleteProps {
431
511
  currentText: string;
432
512
  }
433
513
 
434
- export const Autocomplete = provideModuleToComponent<AutocompleteProps>(AutocompleteModule, ({ inputboxProps, dropdownProps, currentText }) => {
514
+ export const Autocomplete = provideModuleToComponent<AutocompleteProps>(AutocompleteModuleBp, ({ inputboxProps, dropdownProps, currentText }) => {
435
515
  const service = useInject(AutocompleteService);
436
516
 
437
517
  service.inputboxService.currentValue = currentText;
@@ -454,8 +534,6 @@ export const Autocomplete = provideModuleToComponent<AutocompleteProps>(Autocomp
454
534
 
455
535
  This should cover the fundamentals of how you can build a scalable UI by using the `xInjection` Dependency Injection 😊
456
536
 
457
- > **Note:** _Keep in mind that both library ([xInjection](https://www.npmjs.com/package/@adimm/x-injection) & [xInjection ReactJS](https://www.npmjs.com/package/@adimm/x-injection-reactjs)) are still young and being developed, therefore the internals and public API may change in the near future._
458
-
459
537
  ## Unit Tests
460
538
 
461
539
  It is very easy to create mock modules so you can provide them to your components in your unit tests.
@@ -472,13 +550,14 @@ class ApiService {
472
550
  private async sendToLocation(user: User, location: any): Promise<any> {}
473
551
  }
474
552
 
475
- const ApiModule = new ComponentProviderModule({
476
- identifier: Symbol('ApiModule'),
553
+ const ApiModuleBp = new ProviderModule.blueprint({
554
+ id: 'ApiModule',
477
555
  providers: [UserService, ApiService],
478
556
  });
479
557
 
480
- const ApiModuleMocked = new ComponentProviderModule({
481
- identifier: Symbol('ApiModule_MOCK'),
558
+ // Clone returns a `deep` clone and wraps all the `methods` to break their reference!
559
+ const ApiModuleBpMocked = ApiModuleBp.clone().updateDefinition({
560
+ id: 'ApiModuleMocked',
482
561
  providers: [
483
562
  {
484
563
  provide: UserService,
@@ -495,8 +574,8 @@ const ApiModuleMocked = new ComponentProviderModule({
495
574
  ],
496
575
  });
497
576
 
498
- // Now all the dependencies used inside the `RealComponent` will be automatically resolved from the `ApiModuleMocked` component module.
499
- await act(async () => render(<RealComponent module={ApiModuleMocked} />));
577
+ // Now all the dependencies used inside the "RealComponent" will be automatically resolved from the `ApiModuleBpMocked` module.
578
+ await act(async () => render(<RealComponent module={ApiModuleBpMocked} />));
500
579
  ```
501
580
 
502
581
  ## Documentation
@@ -511,6 +590,12 @@ Pull requests are warmly welcomed! 😃
511
590
 
512
591
  Please ensure your contributions adhere to the project's code style. See the repository for more details.
513
592
 
593
+ ## Credits
594
+
595
+ - [Adi-Marian Mutu](https://www.linkedin.com/in/mutu-adi-marian/) - Author of `xInjection` & `xInjection ReactJS`
596
+
514
597
  ---
515
598
 
516
- > For questions, feature requests, or bug reports, feel free to open an [issue](https://github.com/AdiMarianMutu/x-injection-reactjs/issues) on GitHub!
599
+ > [!NOTE]
600
+ >
601
+ > **For questions, feature requests, or bug reports, feel free to open an [issue](https://github.com/AdiMarianMutu/x-injection-react/issues) on GitHub.**