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 🙏

© 2025 – Pkg Stats / Ryan Hefner

react-services-locator

v1.0.1

Published

react services locator

Downloads

28

Readme

Status badge npm version Licence NPM Downloads

React services locator

A very simple (yet effective) implementation of the service locator pattern for React 18+ using Hooks, Context API

Features

This utility is a simple service locator for React applications.

This is a simple service locator for React, my goals while building this library were:

  1. To have a centered place to store all the services that my application needs.
  2. Services can use other services (Almost proper Dependency injection).
  3. To make it easy to understand so that you can copy and paste it into your project and start using it.

How to use

Recommended: Copy and paste 📋

You can directly copy and paste the code from the src folder into your project and start using it. The code is designed to be simple and easy to read.

Why copy and paste you ask?

  1. You can tweak it to your needs
  2. you can see exactly how it works.
  3. You don't have to install a library that will make you worry about support and updates.
  4. It's just 4 files all together, about 100 lines of (relatively readable) typescript code.

If you're not convinced, you can install it via npm:

Npm Installation

Of course, you can install it via npm:

npm install react-services-locator

Basic usage

Create a service

Create a service by extending the AbstractBaseService class:

import { AbstractBaseService, ServicesResolver } from 'react-services-locator'
export class DataService extends AbstractBaseService {
    constructor(provider: ServicesResolver) {
        super(provider);
    }
    getData(url) {
         // fetch data from the url
    }
}

Note that the class should extend the AbstractBaseService class and have a constructor that receives the ServicesResolver as an argument.

Add the ServiceLocatorProvider

Add the ServiceLocatorProvider to the root of your application:

import React from 'react';

import { ServiceLocatorProvider } from 'react-services-locator';

<ServicesProvider
    services={[DataService]}>
    <Consumer />
</ServicesProvider>

Use the useService hook

In your components, use the useService hook to get the service instance:

import { useService  } from 'react-services-locator'

export const Consumer = () => {
    const dataService = useService(DataService);
    
    const [data, setData] = useState(null);
    
    useEffect(() => {
        dataService.getData('https://getmydata.com').then((data) => {
            setData(data);
        });
    }, []);
    
    return <div>
        {data}
       </div>;
};

Service Dependency usage

The purpose of the service locator is to allow services to depend on other services. To demonstrate this, let's create a new service that depends on the DataService:

import { DataService } from './dataService';
import { AbstractBaseService  } from 'react-services-locator'
export class ProfileDataService extends AbstractBaseService {
    constructor(provider: ServicesResolver) {
        super(provider);
    }

    async getProphileData() {
      // use this servicesProvider.getService to get other services  
      const dataService =  this.servicesProvider.getService(DataService)
      dataService.getData('https://getmydata.com/prohile');
    }
}

Notice the AbstractBaseService class has a servicesProvider property that you can use to get other services. This property is injected by the ServiceLocatorProvider, and has only one method: getService.

As you can see, the ProfileDataService depends on the DataService service. This is not classic Dependency Injection, but it's close enough: The main difference is that it's lazy-loaded, so you don't have to worry about the order of the services.

[!IMPORTANT] This also means you can't use get Other services inside the service class constructor. Because the services are not yet registered.

Add the ProfileDataService to the ServiceLocatorProvider:

import React from 'react';
import { ServicesProvider } from 'react-services-locator';

<ServicesProvider
    services={[DataService,ProfileDataService]}>
    <Consumer />
</ServicesProvider>

And use the hook in the Consumer component:

export const Consumer = () => {
    const [dataService, prophileDataService] = useService([DataService,ProfileDataService]);
    
    const [data, setData] = useState(null);
    const [prophileData, setProphileData] = useState(null);
    useEffect(() => {
        dataService.getData('https://getmydata.com').then((data) => {
            setData(data);
        });
        prophileDataService.getProphileData().then((data) => {
            setProphileData(data);
        });
    }, []);
    
    return <div>
        {data}
        {prophileData}
       </div>;
};

Advanced usage - useClass (mainly for testing)

You can use the ServiceLocatorProvider to provide a different service implementation for testing purposes:

import React from 'react';
import { ServicesProvider } from 'react-services-locator';

export class MockDataService extends AbstractBaseService {
    constructor(provider: ServicesResolver) {
        super(provider);
    }
    getData(url) {
        return Promise.resolve('mocked data');
    }
}
// for testing purposes
<ServicesProvider
    services={[{ provide: DataService, useClass : MockDataService },ProfileDataService]}>
    <Consumer />
</ServicesProvider>

In this example, the DataService service is replaced with the MockDataService service. The Consumer component will now use the MockDataService service instead of the DataService service.

Advanced usage - Factory function (for complex initialization)

You can use a factory function to create a service instance, this can be useful when you need to pass arguments to the service constructor:

import React from 'react';
import { ServicesProvider } from 'react-services-locator';

export class HttpService extends AbstractBaseService {
    constructor(provider: ServicesResolver, baseUrl: string) {
        super(provider);
        this.baseUrl = url;
    } 
}

<ServicesProvider
    services={[{
        provide: HttpService,
        useFactory: (provider) => new HttpService(provider, 'https://baseurl.com'),
    }]}>
    <Consumer />
</ServicesProvider>

[!IMPORTANT] Notice that the factory function receives the ServicesResolver as a first argument, so all other arguments should come after it.

Caveats

Services are not available in the service constructor

You can't use get Other services inside the service class constructor. Because the services are not yet registered:

import { DataService } from './dataService';
import { AbstractBaseService  } from 'react-services-locator'
export class ProfileDataService extends AbstractBaseService {
    constructor(provider: ServicesResolver) {
        super(provider);
        const dataService =  this.servicesProvider.getService(DataService); 
        // ❌ error: Service DataService does not exist 
    }
}

No support for multiple ServiceProviders

You can use multiple service providers that some are children of others etc. But, this library was build for only one global service provider.

So if you would build something like this:

<ServicesProvider services={[FirstService]}>>
    <ServicesProvider
        services={[SecondService]}>
        <Consumer />
    </ServicesProvider>
</ServicesProvider>

The Consumer will not be able to get the second service because of how React Context works:

export const Consumer = () => {
    const firstService = useService(FirstService);
    // ❌ error: Service FirstService does not exist 
    return <div>
      
       </div>;
};

So just use it as one global service provider.

Inspiration

This library was inspired by the Angular service locator and the React hooks API. And also react-service-locator library.