Usage
This page provides a practical example of how to use @wroud/di-react
for dependency injection in a React application. We’ll walk through setting up a service container, resolving services using React hooks, and leveraging lazy loading with React Suspense for improved performance.
Setting Up the Service Container
To begin, we create a service container using ServiceContainerBuilder
from @wroud/di
. This allows us to register services that will be injected later into our React components.
import { ServiceContainerBuilder } from "@wroud/di";
import { ServiceProvider } from "@wroud/di-react";
// Create the service container
const builder = new ServiceContainerBuilder();
// Example service
class Logger {
log(message: string) {
console.log(message);
}
}
// Register the service as a singleton
builder.addSingleton(Logger);
// Build the service provider
const serviceProvider = builder.build();
Providing Services in React
Next, we use the ServiceProvider
component to wrap the application, making the registered services available throughout the component tree.
import React from "react";
import { ServiceProvider } from "@wroud/di-react";
import AppContent from "./AppContent";
function App() {
return (
<ServiceProvider provider={serviceProvider}>
<AppContent />
</ServiceProvider>
);
}
export default App;
Resolving Services with useService
Within your components, you can resolve services using the useService
hook. Here’s an example where the Logger
service is used in a component:
import React from "react";
import { useService } from "@wroud/di-react";
import Logger from "./Logger";
function AppContent() {
const logger = useService(Logger);
function handleClick() {
logger.log("Button clicked!");
}
return <button onClick={handleClick}>Click me!</button>;
}
export default AppContent;
Lazy Loading Services with React Suspense
@wroud/di-react
supports lazy loading of services, allowing you to defer the loading of large or rarely used services until they are needed. This is especially useful for improving performance in larger applications. React's Suspense mechanism is automatically used to handle loading states.
Here’s an example of how to set up lazy-loaded services using @wroud/di
's lazy
method:
import { lazy, ServiceContainerBuilder } from "@wroud/di";
import { CounterService } from "./CounterService";
import { ILoggerService } from "./ILoggerService";
import { ConsoleLoggerService } from "./ConsoleLogService";
import { IAdministrationService } from "./administration/IAdministrationService";
// Create the service provider with lazy-loaded services
export function createServiceProvider() {
const serviceProvider = new ServiceContainerBuilder()
.addSingleton(CounterService)
.addSingleton(ILoggerService, ConsoleLoggerService)
.addSingleton(
IAdministrationService,
lazy(() =>
import("./administration/AdministrationService").then(
(m) => m.AdministrationService,
),
),
)
.build();
return serviceProvider;
}
In this example, the AdministrationService
is lazily loaded. When the IAdministrationService
is requested via useService
, the loading will be handled using React Suspense, showing a fallback UI while the service is being loaded.
To resolve the lazy-loaded service in a component, you can use useService
, and React Suspense will automatically handle the asynchronous nature of the service:
import React, { Suspense } from "react";
import { useService, ServiceProvider } from "@wroud/di-react";
import { IAdministrationService } from "./administration/IAdministrationService";
import { createServiceProvider } from "./createServiceProvider";
const serviceProvider = createServiceProvider();
function AdministrationComponent() {
const adminService = useService(IAdministrationService);
return <div>{adminService.getAdminData()}</div>;
}
function App() {
return (
<Suspense fallback={<div>Loading administration service...</div>}>
<ServiceProvider provider={serviceProvider}>
<AdministrationComponent />
</ServiceProvider>
</Suspense>
);
}
export default App;