reactject
TypeScript icon, indicating that this package has built-in type declarations

0.2.21Β β€’Β PublicΒ β€’Β Published

GitHub npm npm

Reactject

πŸ’‰ The TSyringe framework to use dependency injection explicitly in React.

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.


Support the project

β˜•οΈ Buy me a coffee so the open source party never ends.

Buy Me A Coffee

YouTube ▢️ Instagram πŸ“Έ Twitter 🐦 Facebook πŸ‘

godofprogramming.com

Package Sidebar

Install

npm i reactject

Weekly Downloads

1

Version

0.2.21

License

MIT

Unpacked Size

15.3 kB

Total Files

22

Last publish

Collaborators

  • carlossalasamper