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

react-injection

v1.2.3

Published

[![Build Status](https://travis-ci.com/luvies/react-injection.svg?branch=master)](https://travis-ci.com/luvies/react-injection) [![Coverage Status](https://coveralls.io/repos/github/luvies/react-injection/badge.svg?branch=master)](https://coveralls.io/git

Downloads

359

Readme

React Dependency Injection

Build Status Coverage Status

Provides a dependency injection system for React using InversifyJS. Each service can inherit the class ReactiveService<TState> to allow them to trigger component updates when their state changes, allowing for components to use service data in their render functions and respond to changes.

This package provides both a HOC and a useInjection hook.

Example Guide

To define a service, you need to define a class similar to this:

import { injectable } from 'inversify';
import { ReactiveService } from 'react-injection';

interface State {
  data: string;
}

@injectable()
export class DataService extends ReactiveService<State> {
  protected state: State = {
    data: 'sample data',
  };

  public get data(): string {
    return this.state.data;
  }

  public setData(data: string): void {
    this.setState({
      data,
    });
  }
}

You can then create an Inversify container with this service bound to it, and define a module that provides the provider component, HOC decorator, and the hook.

// injection.ts
import { createInjection } from 'react-injection';

export { InjectionProvider, injectComponent, useInject } = createInjection();

You can then consume the service from your components like so:

import React from 'react';
import { injectComponent } from './injection';
import { InjectableProps } from 'react-injection';
// This is assuming that the container is set up using the TYPES
// style from the InversifyJS docs.
import { TYPES } from './types';

interface InjectedProps {
  // You could also name this just 'data' for simplicity.
  dataService: DataService;
}

function App({ dataService }: InjectedProps) {
  return (
    <p>{dataService.data}</p>
  );
}

export default injectComponent<InjectedProps>({
  dataService: TYPES.DataService
})(App);

Note: injectComponent should be usable as a decorator, however TypeScript currently doesn't allow decorators to change the decorated definition's typing currently (since this function removes the injected props from the components typing). If you use babel and JSX/JS, then it should work fine (although I haven't tested this).

Once you have this set up, you can provide the container using the provider component:

ReactDOM.render(
  <InjectionProvider container={container}>
    <App />
  </InjectionProvider>,
  element
);

State mapping

You can map service states directly to props using the second param of injectComponent, which takes in a function that receives all of the injected services, and return an object to map into props. Example:

interface InjectedProps {
  dataService: DataService;
}

interface InjectedStateProps {
  data: string;
}

function App({ data }: InjectedProps & InjectedStateProps) {
  return (
    <p>{data}</p>
  );
}

export default injectComponent<InjectedProps, InjectedStateProps>(
  {
    dataService: TYPES.DataService
  },
  ({ dataService }) => ({
    data: dataService.data,
  })
)(App);

Keep note, the services are injected regardless of whether you use the state mapper or not. It is mostly a helper to allow more direct access to service state & allow proper diffing in componentDidUpdate(...).

Passing container as props directly

The injectComponent decorator supports containers being passed directly as the prop container, however, if you do this, note that you MUST bind the StateTracker class like so:

// Import using a similar statement to this
import { StateTracker } from 'react-injection';

// Bind the class manually
StateTracker.bindToContainer(container);

You need to do this whenever you do not use the InjectionProvider component provided in createInjection.

Hook

To use the hook, you can do something like the following:

// Imports from this module used in the example.
import { useInjection, InjectableProps, StateTracker } from 'react-injection';

// Configure the container from somewhere.
const container = configureContainer();

// Create the React context.
// You can also use the context returned from `createInjection` if you plan to
// mix both kinds.
const context = createContext(container);

// If you use the provider directly, instead of the one given in `createInjection`,
// then you need to remember to do the following.
StateTracker.bindToContainer(container);

// Consume the services in the component.
interface InjectedProps {
  dataService: DataService;
}

// If you define this object outside of the component,
// it will be re-used for each render, and `useInjection`
// will skip re-fetching the same services multiple times
// (this is implmented via `useMemo`).
// You can still use it inline if you want.
const services: InjectableProps<InjectedProps> = {
  dataService: TYPES.DataService,
}

function App() {
  const { dataService } = useInjection(context, services);
  const data = dateService.data;

  return (
    <p>{data}</p>
  );
}

You can also use the useInject function provided in createInjection. Doing so would mean the App component would look like this:

function App() {
  const { dataService } = useInject(services);
  const data = dateService.data;

  return (
    <p>{data}</p>
  );
}