{"id":16229033,"url":"https://github.com/doughtnerd/wrangler-di","last_synced_at":"2026-04-26T12:31:30.139Z","repository":{"id":57109496,"uuid":"418297683","full_name":"doughtnerd/wrangler-di","owner":"doughtnerd","description":"A React library for Dependency Injection via Higher Order Components","archived":false,"fork":false,"pushed_at":"2022-05-20T21:36:18.000Z","size":86577,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-09-26T16:49:39.013Z","etag":null,"topics":["angular","dependency","dependency-injector","injection","inversion-of-control","ioc","react"],"latest_commit_sha":null,"homepage":"https://doughtnerd.github.io/wrangler-di/","language":"HTML","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/doughtnerd.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2021-10-18T01:03:38.000Z","updated_at":"2022-05-13T06:46:51.000Z","dependencies_parsed_at":"2022-08-20T18:20:12.303Z","dependency_job_id":null,"html_url":"https://github.com/doughtnerd/wrangler-di","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/doughtnerd/wrangler-di","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/doughtnerd%2Fwrangler-di","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/doughtnerd%2Fwrangler-di/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/doughtnerd%2Fwrangler-di/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/doughtnerd%2Fwrangler-di/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/doughtnerd","download_url":"https://codeload.github.com/doughtnerd/wrangler-di/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/doughtnerd%2Fwrangler-di/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":32297893,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-26T09:34:17.070Z","status":"ssl_error","status_checked_at":"2026-04-26T09:34:00.993Z","response_time":129,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["angular","dependency","dependency-injector","injection","inversion-of-control","ioc","react"],"created_at":"2024-10-10T12:57:11.367Z","updated_at":"2026-04-26T12:31:30.123Z","avatar_url":"https://github.com/doughtnerd.png","language":"HTML","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Wrangler DI\n An opinionated React library for dependency injection via higher-order components.\n\n[![NPM](https://img.shields.io/npm/v/@doughtnerd/wrangler-di.svg)](https://www.npmjs.com/package/@doughtnerd/wrangler-di) [![JavaScript Style Guide](https://img.shields.io/badge/code_style-standard-brightgreen.svg)](https://standardjs.com)\n\n- [Basic Usage](#usage)\n- [API](#api)\n  - [Injection Tokens](#injection-token)\n  - [Providers](#provider)\n    - [Value Provider](#value-provider)\n    - [Constructor Provider](#constructor-provider)\n    - [Factory Provider](#factory-provider)\n  - [withInjector](#withinjector)\n  - [withProviders](#withproviders)\n- [Typescript Support](#typescript-support)\n- [FAQ](#faq)\n\n## Live Example\n\nThe example app is a very tiny example of this library being used to query anime character data from anime list.\n\nhttps://doughtnerd.github.io/wrangler-di/#/anime-character-details\n\n## Live Example source code\n\nBest way to see how this is used is looking at the Example App source code:\n[Found here](./example/src)\n\n## Install\n\nNpm:\n```bash\nnpm install --save @doughtnerd/wrangler-di\n```\n\nYarn:\n```bash\nnpm add @doughtnerd/wrangler-di\n```\n\n## Usage\n\n\n### Injecting\nFirst, you need to use the `withInjector` function to provide the services that you will inject in child components down the component tree.\n\n#### App.jsx\n```jsx\nimport React from 'react'\n\nimport { withInjector } from '@doughtnerd/wrangler-di'\n\nimport { HTTP_SERVICE, AxiosHTTP } from './services/axiosHttp'\n\nimport { AUTH_SERVICE, AuthService } from './services/authService'\n\nconst appProviders = [\n  { provide: HTTP_SERVICE, useClass: AxiosHttp },\n  { provide: AUTH_SERVICE, useFactory: (httpService) =\u003e new AuthService(httpService), deps: [HTTP_SERVICE] }\n]\n\nconst App = () =\u003e {\n  return (\n    // The rest of your app\n  )\n}\n\nexport default withInjector(\u003cApp /\u003e, appProviders)\n```\n\n\n\n### Accessing Injected Providers\nYou must use the `withProviders` function to wrap the component you wish to inject. \n\n```jsx\nimport React from 'react'\n\nimport { withProviders } from '@doughtnerd/wrangler-di'\n\nimport { AUTH_SERIVCE } from './services/authService'\n\n/*\n * The component you use will have a `deps` array prop added. \n * Each element in the array is the injected provider you define when you use `withProviders`\n */\nconst SignInPage = ({deps: [authService]}) =\u003e {\n\n  return (\n    \u003cform onSubmit={(e) =\u003e {\n        e.preventDefault()\n        authService.login(e.target.username.value, e.target.password.value)\n      }\n    }\u003e\n      \u003cinput name=\"username\" type=\"text\"\u003e\u003c/input\u003e\n      \u003cinput name=\"password\" type=\"password\"\u003e\u003c/input\u003e\n\n      \u003cbutton type=\"submit\"\u003eSign In\u003c/button\u003e\n    \u003c/form\u003e\n  )\n}\n\n// `AUTH_SERVICE` is the `Injection Token` of the thing you're trying to inject.\nexport default withProviders(SignInPage, [ AUTH_SERVICE ])\n```\n\n## API\n\n### Injection Token\nAn injection token is a string that the injector uses to uniquely identify providers. \nThis string can be anything you like but __MUST__ be unique within a single injector.\n\nA Provider object's ```provide``` key is an Injection Token.\n\nIt is recommended that this string get set to some constant in order to reduce mistyping or 'magic string' issues.\n\n```js\n{ \n  provide: 'HttpService', // \u003c- This is an injection token\n  useClass: MyHttpService \n}\n```\n\n### Provider\nA provider is something that the injector will use to create the services that are consumed within an app.\n\nThere are three different types of providers.\n\n#### Value Provider\n\u003e Used to provide value objects or functions.\n```js\n{ provide: 'FooBarProvider', useValue: { foo: 'bar' } }\n```\n\n#### Constructor Provider\n\u003e Used to provide a class that the injector will create for you\n```js\n{ provide: 'HttpService', useClass: MyHttpService }\n```\n\n#### Factory Provider\n\u003e Used to provide a factory function that will control how the provider is created.\n\u003e Can be used with ```deps```, which is an array of injection tokens of other providers.\n```js\n{ provide: 'AuthService', useFactory: (httpService) =\u003e new AuthService(httpService), deps: ['HttpService'] }\n```\nIf deps are used, the function assigned to ```useFactory``` will be called with deps in the same order as they are in the ```deps``` array.\n```js\n{ \n  provide: 'AuthService', \n  useFactory: (httpService, graphqlService) =\u003e { // Notice httpService and graphqlService are in the same order as 'deps'\n    return new ApiService(httpService, graphqlService)\n  }, \n  deps: ['HttpService', 'GraphqlService'] \n}\n```\n\n### withInjector\nThis function takes two parameters: The component you want to wrap with an injector and the array of providers you want to make available for injection.\n```jsx\nconst appProviders = [\n  { provide: HTTP_SERVICE, useClass: AxiosHttp },\n  { provide: AUTH_SERVICE, useFactory: (httpService) =\u003e new AuthService(httpService), deps: [HTTP_SERVICE] }\n]\n\n// This is also correct\nwithInjector(\u003cApp /\u003e, appProviders)\n\n// So is this\nwithInjector(\u003cApp initialAppConfig={ {foo: \"bar\"} } /\u003e, appProviders)\n\n// This is NOT correct\nwithInjector(App, appProviders)\n\n```\n\nYou don't have to provide everything in one injector. If you have a service that only needs to be injected for one page, provide it at that page level. This library is smart enough to resolve hierarchical dependencies. \n\nExample:\n```jsx\n// App.jsx\nimport MyFavoritesPage from './MyFavoritesPage'\n\nconst appProviders = [\n  { provide: HTTP_SERVICE, useClass: AxiosHttp }\n]\n\nconst App = () =\u003e {\n  return (\n    \u003cMyFavoritesPage /\u003e\n  )\n}\nexport default withInjector(\u003cApp /\u003e, appProviders)\n// ------------ END OF FILE ----------------------\n\n// MyFavoritesPage.jsx\nimport { FavoritesApi } from './favoritesApi'\n\nconst pageProviders = [ \n  { provide: 'FavoritesApi', useFactory: (httpService) =\u003e new FavoritesApi(httpService), deps: [HTTP_SERVICE] } \n]\n\nconst MyFavoritesPage = ({deps: [favoritesApi]}) =\u003e {\n  return (\n    \u003cul\u003e\n      {favoritesApi.getFavorites().map(favorite =\u003e \u003cli key={favorite}\u003e{favorite}\u003c/li\u003e)}\n    \u003c/ul\u003e\n  )\n}\n\nconst MyFavoritesPageWithDeps = withProviders(MyFavoritesPage, [ 'FavoritesApi' ])\n\nexport default withInjector(\u003cMyFavoritesPageWithDeps /\u003e, pageProviders)\n// ------------ END OF FILE ----------------------\n```\n\n### withProviders\nThis function takes two parameters: The component you wish to inject with dependencies, and an array of Injection Tokens. It returns a HOC that can then be passed any props that are on the original component minus the `deps` array.\n```jsx\n/**\n * If props for the SignInPageBase component are:\n * { deps: [AuthService] }\n * \n * This is all you need to do to inject (assuming you've used `withInjector` somewhere above in the component tree)\n */\nconst SignInPage = withProviders(SignInPageBase, [ 'AuthService' ])\n\n// No props need to be provided, the HOC has taken care of the `deps` array\nreturn \u003cSignInPage /\u003e\n\n/**\n * If you have more props than the `deps` array, for example:\n * { allowGoogleSignIn: boolean, deps: [AuthService] }\n * \n * You are still able to set the other props like you would with a normal component\n */\nconst SignInPage = withProviders(SignInPageBase, [ 'AuthService' ])\n\n// You can set the prop without having to set the `deps` prop. The HOC still handles setting that and passes any other props to the `SignInPageBase` component\nreturn \u003cSignInPage allowGoogleSignIn={false} /\u003e\n```\n\n## Typescript Support\nThis library was built in TS and hopefully provides useful types you can use. The best way to see how to use Typescript here is to look at the example project [found here](./example/src)\n\n## FAQ\n### Why are there no hooks or contexts that I can use?\nFirst, because context is useful in many scenarios but is both over-used and used inappropriately. Often using context makes the component that uses it harder build, test, and re-use.\n\nSecond, because context and hooks defeat the purpose of using dependency injection in the first place - especially when those hooks/contexts involve side-effects that change the world ***outside*** of the component.\n\n## Warnings - Possible errors if you don't follow\n- Don't update the array used in withProviders at runtime\n- Don't update the array used in withInjector at runtime\n- Don't mutate Value Providers\n- Don't use `deps` with Constructor Providers\n\n\n## License\n\nMIT © [doughtnerd](https://github.com/doughtnerd)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdoughtnerd%2Fwrangler-di","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdoughtnerd%2Fwrangler-di","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdoughtnerd%2Fwrangler-di/lists"}