npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

bubu-di

v0.0.2

Published

react dependency injection library

Downloads

11

Readme

travis ci codecov

Intro

A lightweight dependency injection lib for react.

  • Typescript friendly
    • You should depend on interface, not on implementation or runtime typings.
  • Zero dependency
    • Does not depend on reflect-metadata.
  • Automatic instance creation and destruction based on react lifecycles.
  • When injecting service, support both class property decorator injection and react-hook injection.

一个轻量级的react di库

  • Typescript 友好
    • 你终于可以依赖interface来注入了, 而不是依赖实现或者其他什么运行时类型信息.
  • 零依赖
    • 甚至不依赖reflect-metadata
  • 跟组件生命周期同步的实例自动创建和销毁
  • 注入服务的时候, 既支持类属性装饰器, 又支持react-hook

Usage

把大象装冰箱有3步, 用bubu-di在react项目引入依赖注入却有4步.

Step1 创建一个接口

import {createServiceId} from "bubu-di"
interface IA {
    a():string
}
export const IA = createServiceId<IA>("A")

interface IB {
    b():string
}
export const IB = createServiceId<IB>("B")

Step2 实现这个接口

// b.ts
import {inject} from "bubu-di"

class AImpl extends IA {
    a(){
        return "hello world"
    }
}

class BImpl implements IB {
    //凡是由bubu-di来实例化的服务, 都可以注入别的由bubu-di实例化的服务, 例如
    @inject(IA)
    a: IA

    b(){
        return "hello"+ this.a.a()
    }
}

Step3 在组件树上某个节点提供这个接口的实现

注意这个pipe函数, bubu-di并不提供, 需要引入别的或者自己实现. 很多库都有类似函数, 例如redux的compose()也可以, 但是composepipe顺序是相反的, 如果同一个里存在相互依赖需要注意这一点.

import {use} from "bubu-di"
import {pipe} from "rxjs"
import {useService, IInstantiationService} from "bubu-di"
import {IA,IB} from "interface"
import {AImpl} from "a"
import {BImpl} from "b"

export function ServiceRegistry({children}:{children?:React.ReactNode}){

    const container = useService(IInstantiationService)

    return pipe(
        container.provide(IA, AImpl, {aOption1: "bar"}),
        container.provide(IB, BImpl),
    )(children)
}


// somewhere else:
// Main 组件及其下面所有子孙组件中就能注入IA和IB了
function App(){
    return <ServiceRegistry>
        <Main />
    </ServiceRegistry>
}

Step4 在需要用到服务接口的地方, 按接口注入依赖

import {IB} from "interfaces"
import {useService} from "bubu-di"

function C(){
    const b = useService(IB)
    return <div>{b.b()}</div>
}

或者在第2步中提到的一样, 在服务之间互相注入.

Bonus 覆盖实现

你可以在一个子树中覆盖某些接口的具体实现, 没有被覆盖的接口会继承父树提供的实现.

class AlternativeA implments IA {
    a(){
        return "f*** this world"
    }
}

function SomeSubRoute(){
    return <SomeSubRouteServiceRegistry>
        <SomeSubRouteChild />
    </SomeSubRouteServiceRegistry>
}

export function SomeSubRouteServiceRegistry({children}:{children?:React.ReactNode}){

    const container = useService(IInstantiationService)

    const subContainer = container.useNewNode()

    return pipe(
        subContainer.provide(IA, AlternativeA),
        //由于IB依赖IA, 必须重新explicitly提供IB, 不然就会复用父级的IB
        //explicit is better than implicit
        subContainer.provide(IB, BImpl),
    )(children)

}

function SomeSubRouteChild(){

    const a = useService(IA) // here a is an instance of "AlternativeA"

    const b = useService(IB) // if IInstantiationService cannot find a service registry, it will bubble up to its parent node, which will return an instance of BImpl

    return <div></div>
}

Thanks

  • The injector idea comes from react-ioc
  • The service id idea comes from vscode