reactject
v0.2.21
Published
React adapter of the TSyringe dependency injection container π
Downloads
63
Maintainers
Readme
Reactject
Introduction
π Welcome to this framework that gives you full control over dependency management at runtime in React apps.
To keep it short, Reactject is the necessary piece to connect your React application with the dependency container in an elegant way.
Additionally the API adds new features and decorators to enhance the development experience.
Reactject is built on Microsoft's TypeScript efficient open source dependency container TSyringe.
Reasons to use Reactject
These are the reasons you didn't know why you should install Reactject in your React project.
React TSyringe adapter
Reactject exposes the TSyringe container and adds optimized hooks to resolve dependencies in functional components.
const MyComponent = () => {
const gitHubService = useResolve(GitHubService);
// TODO: use githubService to interact with the API
return <div>This is my component</div>;
};
Full execution control
Reactject works as a TSyringe wrapper to decide when and where the modules registration begins.
The "module" concept is very similar to the Angular's one, but each module can choose between to use a child container or to register dependencies in the parent module container.
import {
ReactjectModule,
Reactject,
module,
DependencyContainer,
} from "reactject";
import GithubService from "./GithubService";
@module()
class AppModule extends ReactjectModule {
register(container: DependencyContainer) {
super(container);
container.registerSingleton(GithubService);
}
}
Reactject.start(AppModule);
Structured dependencies
Use our @module
decorator to specify the submodules of a module. Modules will be registered recursively after Reactject.start(AppModule)
execution.
@module({
submodules: [PaymentModule, SharedModule],
})
class AppModule extends ReactjectModule {}
Reactject.start(AppModule);
All the dependencies of both PaymentModule
and SharedModule
will be registered when Reactject starts.
On-demand features
We are aware that there are still not too many functionalities nor is the direction of the project well defined.
But we can see this situation as an opportunity to listen to the community and develop, after an evaluation, the features that are most requested.
Support us and participate in the community to be part of the history of Reactject.
Installation
npm install reactject
yarn add reactject
Usage
Modules
In Reactject you register your dependencies organized by modules and when you start the root module (AppModule) the framework register all the submodules recursively.
Think modules are a pattern to group your dependencies and scope them with the container
prop of the @module
decorator. Dependencies in a module are by default registered in the global app container.
// GithubService.ts
import { injectable } from "reactject";
import axios from "axios";
@injectable()
class GitHubService {
public readonly baseUrl = "https://api.github.com";
public async getUser(username: string) {
const response = await axios.get(`${this.baseUrl}/users/${username}`);
return response.data;
}
}
export default GitHubService;
// GithubModule.ts
import { ReactjectModule, Reactject, module } from "reactject";
import GithubService from "./GithubService";
@module({
container: "child",
})
export class GithubModule extends ReactjectModule {
register(container: DependencyContainer) {
super(container);
container.registerSingleton(GithubService);
}
}
// AppModule.ts
import { ReactjectModule, Reactject, module } from "reactject";
import { GithubModule } from "./GithubModule";
@module({
submodules: [GithubModule],
})
class AppModule extends ReactjectModule {}
Reactject.start(AppModule);
Registering
Register the classes or interfaces you are going to use as dependencies using the TSyringe decorators.
Check the TSyringe container documentation if you have any questions about its use.
Mark your class as @injectable and register it explicitly in a module.
// GithubService.ts
import { injectable } from "reactject";
import axios from "axios";
@injectable()
class GitHubService {
public readonly baseUrl = "https://api.github.com";
public async getUser(username: string) {
const response = await axios.get(`${this.baseUrl}/users/${username}`);
return response.data;
}
}
export default GitHubService;
// GithubModule.ts
import { ReactjectModule, Reactject, module } from "reactject";
import GithubService from "./GithubService";
@module()
export class GithubModule extends ReactjectModule {
register(container: DependencyContainer) {
super(container);
container.registerSingleton(GithubService);
}
}
Resolving
Resolve the dependencies you have registered in the scopes where you need to use them.
Classes
To resolve dependencies within javascript classes we will not have to do anything special, since TSyringe is prepared to inject them through the constructor.
The following piece of code would allow us to inject dependencies into a class component.
import { inject } from "reactject";
import GitHubService from "../services/GitHubService";
class MyComponent {
constructor(
@inject(GitHubService) private readonly gitHubService: GitHubService
) {}
private getUser() {
return this.gitHubService.getUser("carlossalasamper");
}
private render() {
return <div>This is my component</div>;
}
}
export default MyComponent;
Hooks
Access the container dependencies transparently using the hooks we have prepared.
import { useResolve } from "reactject";
import GitHubService from "../services/GitHubService";
const MyComponent = () => {
const gitHubService = useResolve(GitHubService);
useEffect(() => {
gitHubService.getUser("carlossalasamper");
}, []);
return <div>This is my component</div>;
};
export default MyComponent;
Third parties
β οΈ Creating classes that wrap the integrations would oversize the use of dependency injection in React and would also be very expensive to maintain.
To use our dependencies in the integration code of third parties that do not offer a class through which we can inject the objects that we need, we will access the container directly.
For example, to access the container from a Redux Toolkit AsyncThunk we would do it as follows:
import { container } from "reactject";
import { createAsyncThunk, createSlice } from "@reduxjs/toolkit";
import GitHubService from "../services/GitHubService";
const getUser = createAsyncThunk(
"github/getUser",
async (username: string, thunkAPI) => {
const gitHubService = container.resolve(GitHubService);
return gitHubService.getUser(username);
}
);
Examples
In the /examples folder you will find demo React applications that are using Reactject.