Skip to main content

Introduction

Obsidian is a dependency injection container with first-class support for React and React Native applications.

Get started by following the installation guide bellow. Or try Obsidian immediately in the Online Playground.

The 2 steps tutorial for injecting dependencies with Obsidian

Step 1: Declare how dependencies should be created

Define a singleton graph that is instantiated once and is retained throughout the lifespan of the application. All dependencies it provides are also singletons. The graph bellow provides two dependencies that can be injected: fooService and barManager.

A singleton graph that provides two dependencies
import {Singleton, Graph, ObjectGraph, Provides} from 'react-obsidian';


@Singleton() @Graph()
export class ApplicationGraph extends ObjectGraph {

// fooService requires a barManager so it receives one as a parameter.
@Provides()
fooService(barManager: BarManager): FooService {
return new FooService(barManager);
}


@Provides()
barManager(): BarManager {
return new BarManager();
}
}

Step 2: Inject the dependencies

Obsidian can inject dependencies into components, hooks, and classes.

Injecting React functional components essentially revolves around two things: declaring the required dependencies in the components's props and exporting an injected component using the injectComponent function.

MyComponent.tsx
import {DependenciesOf, injectComponent} from 'react-obsidian';
import {ApplicationGraph} from './ApplicationGraph';

// 1. Declare which dependencies should be injected.
type Props = DependenciesOf<ApplicationGraph, 'fooService'>; // {fooService: FooService}

// 2. Implement the component.
const myComponent = ({fooService}: Props) => {
// Do something useful with fooService
}

// 3. Export the injected component.
export default injectComponent(myComponent, ApplicationGraph);

Now we can use the injected component without providing its dependencies manually:

SomeComponent.tsx
import MyComponent from './MyComponent';

const SomeComponent = () => {
// 4. Render the component - its dependencies are resolved automatically by Obsidian.
return <MyComponent />;
}

Features

  • ⚛️ Inject all React constructs
    • Functional components
    • Hooks
    • Class components
  • 🛠 Improve code structure
    • Easily write object-oriented code with Single Responsibility in mind
    • Eliminate circular dependencies
    • Avoid implicit dependencies to make your code easier to reason about
  • ❤️ Developer experience
    • Seamlessly integrates into existing projects
    • Easy to adopt gradually
    • Scales well
    • Idiomatic API that's easy to understand

Design principles

React Obsidian is guided by the principles of the Dependency Injection pattern, but does not strictly follow them. We allowed ourselves a degree of freedom when designing the library in order to reduce boilerplate code and library footprint.

  • Easy to start - Obsidian requires very little code to get you started. Once you declare a graph, using it to inject dependencies requires as little as two lines of code.
  • Intuitive API - The API should be verbose and understandable even to new users without prior experience with Dependency Injection.
  • Minimal boilerplate - Require the bare minimum in order to construct dependencies and resolve them.