Dependency Injection In ReactJS

As a backend developer writing code that follows design principles and patterns is my basic instinct. When I started Web app development, I always missed the dependency injection principle which enables to separate the UI from business logic. Basically, I wrote GET POST requests in the UI component to get data from backend and POST data to the backend.

This was true for logging, when developing I used to use console.log everywhere, but forgot to remove them in production. Then after noticing them would manually search them and remove the logs.

At last, I decided to search, if there is any dependency injections providers in react JS. Then I came across Jpex npm package which enables dependency registration and resolution when required.

This article is about showing about usage of react-jpex for dependency injection.

Pre-Requisites

  1. Basic knowledge of React JS
  2. Basic Knowledge of TypeScript (although same concepts can be applied to JS)

Jpex

Jpex is an Inversion of Control framework. Register dependencies on a container, then resolve them anywhere in your application.

Jpex uses babel to infer type interfaces at build time. You can do this with one of several methods,

  • @jpex-js/babel-plugin
  • @jpex-js/rollup-plugin
  • @jpex-js/webpack-plugin

React-Jpex

React-Jpex is just a simple context wrapper around jpex.

To explain how React-Jpex is used I will take an example of Console logging. Often logging various states of the UI at various places in the component is a habit of developers. For example most common place is to log the response from the API. These logs are very important during development but when the code moves to production, then these logs need to be removed which is a tedious task. Also, these logs will be required to debug any issues. So maintaining the print statements is useful. Developers need an easy way to switch on and off the logs in the code, this can be achieved using Dependency Injection Principle.

When users want the prints then inject Console logger in code, if not inject nulllogger which will ignore the prints.

An example implementation is shown below.

Create a react JS app (I Use React Next JS with Typescript app for this example)

pnpm create next-app -- --ts

Note: To create Next JS app, check out the blog here.

Install below npm packages,

  1.  Jpex
  2. react-jpex
  3. @jpex-js/babel-plugin

Create a file called Di.ts in service folder to register all your interfaces and classes.

Below are the contents of the file,

import {useJpex} from 'react-jpex';
export default function getDiContainer(): any {
    const jpex = useJpex();
    jpex.constant < ILogger > ('console', new ConsoleLogger());
    jpex.constant < ILogger > ('null', new NullLogger());
}
export interface ILogger {
    Log(msg: string): void
}
export class ConsoleLogger implements ILogger {
    Log(msg: string): void {
        console.log(msg)
    }
}
export class NullLogger implements ILogger {
    Log(msg: string): void {
        //console.log(msg)
    }
}

To register the DI provider, open the _app.tsx file and make following changes,

import '../styles/globals.css'
import type { AppProps } from 'next/app'
import {Provider} from "react-jpex";
import getDiContainer from "../services/di";
function MyApp({ Component, pageProps }: AppProps) {
  return (
      <Provider value={getDiContainer()}>
        <Component {...pageProps} />
      </Provider>
  )
}
export default MyApp

Then you can inject dependency like below as required either to print or no-print the logs.

const jpex = useJpex();
//const logger = jpex.resolve<ILogger>("console");
const logger = jpex.resolve < ILogger > ("null");
useEffect(() => {
            // just for testing logs
            logger.Log("Message is logged in useEffect");
        }

 Resolve using “console” to print the logs else use “null”.

Full code is available on github.

Conclusion

React-Jpex provides a way to register code dependencies and resolve them as required. This article shows how to use React-Jpex to register 2 types of loggers to print logs during development and suppress them during production.