19 | count module 20 |
21 |45 | Counter 46 |
47 |48 | Count: 49 | 0 50 |
51 | 56 | 61 |16 | Open you browser devtools console... and start clicking on buttons ;) 17 |
18 |19 | Clicked: {counterService.value} times{' '} 20 | {' '} 21 | {' '} 22 | {' '} 25 | 28 |
29 |(Component: ComponentType
) => 7 | Component.displayName || 8 | Component.name || 9 | (Component.constructor && Component.constructor.name) || 10 | 'Component' 11 | 12 | export const createHOCName =
(
13 | Wrapper: ComponentType
15 | ) =>
16 | `${getComponentDisplayName(Wrapper)}(${getComponentDisplayName(
17 | WrappedComponent
18 | )})`
19 |
20 | // tslint:disable-next-line:no-empty
21 | export const noop = () => {}
22 |
23 | export const tuple = {repo.description}
16 | Clicked: {counterService.value} times{' '}
17 | {' '}
18 | {' '}
19 | {' '}
22 |
25 | Clicked: {counterService.state.count} times
18 |
19 |
20 |
23 |
26 | There are no messages in store... & {
25 | WrappedComponent: OriginalComponent
26 | }
27 |
28 | export type InstanceTypes
48 | Count:
49 | 0
50 |
19 | Open you browser devtools console... and start clicking on buttons ;)
20 |
72 | Count:
73 | 0
74 | Count: {counterService.state.count} Count: {counterService.state.count}
90 | Clicked: {counterService.state.count} times
91 |
92 |
93 |
96 |
99 | @{username} Repos
13 |
19 | {repo.name}
20 |
21 | )}
22 | {repo.description && (
23 |
14 | )}
15 |
16 |
17 | {bio.name &&
31 | Messages
15 | Top Heroes
28 | {hero.name}
37 |
19 | count module
20 |
21 |
45 | Counter
46 |
47 | Hero Search
52 |
53 | this.search(this.searchResultRef.current!.value)}
59 | />
60 |
61 |
62 | {heroes.map((hero) => (
63 |
68 | Counter app
18 | Counter component with CounterService instance
24 |
27 |
28 |
37 | Counter component with MultiplyCounterService instance
38 |
39 |
40 | multiply by 2 and uses enhanced logger
41 |
42 |
48 |
49 |
58 | Counter component with MultiplyCounterService instance
59 |
60 | multiply by 4
61 | {uppercase(hero.name)} Details
43 | My Heroes
31 |
32 |
44 | {heroes.map((hero) => (
45 |
59 | >
60 | )
61 | }
62 | componentDidMount() {
63 | this.props.heroService.getHeroes().then((heroes) => {
64 | this.setState({ heroes })
65 | })
66 | }
67 |
68 | private delete(hero: Hero) {
69 | const heroesWithoutRemoved = this.state.heroes.filter((h) => h !== hero)
70 |
71 | this.props.heroService.deleteHero(hero).then(() => {
72 | this.setState((prevState) => ({
73 | heroes: [...heroesWithoutRemoved],
74 | }))
75 | })
76 | }
77 |
78 | private add(name: string) {
79 | name = name.trim()
80 | if (!name) {
81 | return
82 | }
83 |
84 | const newHero = { name } as Hero
85 | this.props.heroService.addHero(newHero).then((hero) => {
86 | this.setState(
87 | (prevState) => ({
88 | heroes: [...prevState.heroes, hero],
89 | }),
90 | () => (this.heroNameRef.current!.value = '')
91 | )
92 | })
93 | }
94 | }
95 |
--------------------------------------------------------------------------------
/examples/tour-of-heroes/src/app/app.tsx:
--------------------------------------------------------------------------------
1 | // tslint:disable:jsx-no-lambda
2 |
3 | import { DependencyProvider, Inject } from '@martin_hotell/rea-di'
4 | import React, { Component } from 'react'
5 | import {
6 | BrowserRouter as Router,
7 | NavLink,
8 | Redirect,
9 | Route,
10 | Switch,
11 | } from 'react-router-dom'
12 |
13 | import { Dashboard, HeroDetail, Heroes } from './components'
14 | import { HeroService } from './hero.service'
15 | import { HttpClient, HttpClientConfig } from './http-client.service'
16 | import { Messages, MessageService } from './messages'
17 |
18 | export class App extends Component {
19 | title = 'Tour of Heroes'
20 | render() {
21 | return (
22 | {injectorLabel}
41 |
42 | Registered Providers: {json(registeredProvidersNames)}
43 |
44 |
42 | count module
43 |
44 |
69 | Counter
70 |
71 | Counter
16 | Counter
44 | Something went wrong.
96 |
99 | {this.state.errorInfo.componentStack}
100 | {this.props.title}
19 | {JSON.stringify(props)}
128 | }
129 |
130 | const InjectConsumerEnhanced = withInjectables({
131 | car: Car,
132 | engine: optional(Engine),
133 | })(InjectConsumer)
134 |
135 | it(`should properly resolve optional injection on component level`, () => {
136 | const Test = withDependencyProvider(Car)(() => {
137 | return (
138 | {this.props.title}
21 | {JSON.stringify(engine)}
232 | `
187 |
188 | Abstract class which implements `setState` on your service class. If you wanna handle state within your service you need to extend from this Base class and implement `state`, exactly like you would with `React.Component`
189 |
190 | ```ts
191 | const initialState = {
192 | count: 0,
193 | }
194 |
195 | @Injectable()
196 | class CounterService extends StatefulBuilding a github user search
258 |
259 | Let's build a simple github user search app, by leveraging `rea-di`.
260 |
261 | This is what we're gonna build: 
262 |
263 | And this is how DI tree will look like 
264 |
265 | > For complete implementation/demo checkout [examples](./examples/github-user)
266 |
267 | 1. Implementing GithubUserService
268 |
269 | We need implement our service, which is a pure javascript class with to encapsulate logic for fetching user data from github. To make it work with `rea-di` and `injection-js` we need to annotate our class with `@Injectable()` decorator. Now we can leverage dependency injection via constructor injection, and inject an `HttpClient` [axios-http](https://github.com/Hotell/axios-http), which will be used for XHR.
270 |
271 | We will implement 3 methods, for getting user info, user repos and one aggregated method for getting both.
272 |
273 | ```tsx
274 | // user.service.ts
275 | import { HttpClient } from '@martin_hotell/axios-http'
276 | import { Injectable } from 'injection-js'
277 |
278 | import { GithubUserRepo } from './repo.model'
279 | import { GithubUser } from './user.model'
280 |
281 | const endpointPath = 'users'
282 |
283 | @Injectable()
284 | export class GithubUserService {
285 | constructor(private http: HttpClient) {}
286 | getRepos(username: string) {
287 | return this.http.getGitHub User Search 👀
322 |