Skip to content

Commit

Permalink
Merge pull request #2 from providerx/firebase-hosting
Browse files Browse the repository at this point in the history
Fixed api and hosted to firebase
  • Loading branch information
srinivasayush authored Apr 7, 2021
2 parents 5f90f96 + ae3dfc9 commit 68d88d4
Show file tree
Hide file tree
Showing 15 changed files with 420 additions and 332 deletions.
60 changes: 31 additions & 29 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,51 +1,53 @@
## React-ProviderX

A React state management library built on top of RxJS and Observables

## Usage:

The library will cache data within your ObservableProvider, so you can grab values from a provider with the `useProvider`
hook - without re-fetching data.

```tsx
import React from 'react'
import { useProvider, ObservableProvider, refresh } from 'react-providerx'
import { from } from 'rxjs'
import { tap } from 'rxjs/operators'

export const userResponseProvider$ = ObservableProvider.autoDispose((ref) => {
const fetchErrorApi = async () => {
const response = await fetch('https://jsonplaceholder.typicode.com/users/1')
const json = await response.json()
return json
}

return from(fetchErrorApi()).pipe(
catchError((error: Error) => {
console.log('there was an error in fetching the api')
ref.maintainState = false
return throwError(error)
}),
)
})
const fetchErrorApi = async () => {
const response = await fetch('https://jsonplaceholder.typicode.com/users/1')
const json = await response.json()
return json
}

return from(fetchErrorApi()).pipe(
catchError((error: any) => {
ref.maintainState = false
return ref.error(error)
})
)
})

const Component: React.FC = () => {
const { isLoading, data, error } = useProvider(userResponseProvider$)
if(isLoading) {
return (
<div>
Waiting For Data...
</div>
)
}
return (
<div>
{data}
<button onClick={() => refresh(userResponseProvider$)}>Click to refresh</button>
</div>
)
const { isLoading, data, error } = useProvider(userResponseProvider$)
if (isLoading) {
return <div>Waiting For Data...</div>
}
return (
<div>
{data}
<button onClick={() => refresh(userResponseProvider$)}>
Click to refresh
</button>
</div>
)
}
```

## Supporters
[![Stargazers repo roster for @DudeBro249/providerx](https://reporoster.com/stars/DudeBro249/providerx)](https://github.com/DudeBro249/providerx/stargazers)

[![Stargazers repo roster for @DudeBro249/providerx](https://reporoster.com/stars/DudeBro249/providerx)](https://github.com/providerx/providerx-js/stargazers)

## License

[Apache License 2.0](https://choosealicense.com/licenses/apache-2.0/)
66 changes: 40 additions & 26 deletions react-providerx/src/hooks/useProvider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,36 +3,50 @@ import { AutoDisposeObservableProvider } from '../observableProvider/autoDispose
import { BaseObservableProvider } from '../observableProvider/base'

type UseProviderValues<T> = {
isLoading: boolean
data: T
error: any
isLoading: boolean
data: T
error: any
}

export const useProvider = <T>(provider: BaseObservableProvider<T>) => {
const [currentValue, setCurrentValue] = useState<T | null>(null)
const [currentError, setCurrentError] = useState<any | null>(null)
const [currentValue, setCurrentValue] = useState<T | undefined>(undefined)
const [currentError, setCurrentError] = useState<any | undefined>(undefined)
const [isLoading, setLoading] = useState<boolean>(false)

useEffect(() => {
const handleError = (error: any) => {
setCurrentError(error)
}
useEffect(() => {
const handleError = (error: any) => {
console.log('useProvider hook: The value of error is: ')
console.log(error)
setCurrentError(error)
}

const handleValue = (value: T) => {
setCurrentValue(value)
}
const [valueSubscription, errorSubscription] = provider.subscribe(handleValue, handleError)
return () => {
valueSubscription.unsubscribe()
errorSubscription.unsubscribe()
if(provider instanceof AutoDisposeObservableProvider) {
provider.registerUnsubscribe()
}
}
}, [provider])
const handleLoading = (loading: boolean) => {
console.log('useProvider hook: The value of loading is: ')
console.log(loading)
setLoading(loading)
}

return {
isLoading: currentValue === undefined && currentError === undefined,
data: currentValue,
error: currentError,
} as UseProviderValues<T>
const handleValue = (value: T | undefined) => {
console.log('useProvider hook: Got a value down the pipe: ')
console.log(value)
setCurrentValue(value)
}
const [valueSubscription, errorSubscription] = provider.subscribe(
handleValue,
handleError
)
return () => {
valueSubscription.unsubscribe()
errorSubscription.unsubscribe()
if (provider instanceof AutoDisposeObservableProvider) {
provider.registerUnsubscribe()
}
}
}, [])

return {
isLoading: currentValue === undefined && currentError === undefined,
data: currentValue,
error: currentError,
} as UseProviderValues<T>
}
24 changes: 12 additions & 12 deletions react-providerx/src/models/providerReference.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,18 @@
import { throwError } from "rxjs"
import { throwError } from 'rxjs'

export class ProviderReference {
executionError?: any
error(error: any) {
this.executionError = error
return throwError(error)
}
executionError?: any

error(error: any) {
this.executionError = error
return throwError(error)
}
}

export class AutoDisposeProviderReference extends ProviderReference {
maintainState: boolean
constructor(maintainState?: boolean) {
super()
this.maintainState = maintainState ?? true
}
maintainState: boolean
constructor(maintainState?: boolean) {
super()
this.maintainState = maintainState ?? true
}
}
113 changes: 58 additions & 55 deletions react-providerx/src/observableProvider/autoDispose.ts
Original file line number Diff line number Diff line change
@@ -1,64 +1,67 @@
import { BehaviorSubject, from, Observable, Subscription } from "rxjs";
import { AutoDisposeProviderReference } from "../models/providerReference";
import { BaseObservableProvider } from "./base";
import { BehaviorSubject, from, Observable, Subscription } from 'rxjs'
import { AutoDisposeProviderReference } from '../models/providerReference'
import { BaseObservableProvider } from './base'

export class AutoDisposeObservableProvider<T> extends BaseObservableProvider<T> {
_valueSubject$: BehaviorSubject<T> | BehaviorSubject<undefined>
_errorSubject$: BehaviorSubject<T> | BehaviorSubject<undefined>
observableCreator
ref: AutoDisposeProviderReference
_observable$: Observable<T>
_internalSubscription?: Subscription
export class AutoDisposeObservableProvider<
T
> extends BaseObservableProvider<T> {
observableCreator
ref: AutoDisposeProviderReference
_observable$: Observable<T>
_internalSubscription?: Subscription

constructor(observableCreator: (ref: AutoDisposeProviderReference) => Observable<T>) {
super(observableCreator)
this.observableCreator = observableCreator
this.ref = new AutoDisposeProviderReference(false)
this._observable$ = new Observable()
this._valueSubject$ = new BehaviorSubject(undefined)
this._errorSubject$ = new BehaviorSubject(undefined)
constructor(
observableCreator: (ref: AutoDisposeProviderReference) => Observable<T>
) {
super(observableCreator)
this.observableCreator = observableCreator
this.ref = new AutoDisposeProviderReference(false)
this._observable$ = new Observable()
}

static fromPromise<S>(
promise: () => Promise<S>
): AutoDisposeObservableProvider<S> {
return new AutoDisposeObservableProvider<S>(() => from(promise()) as any)
}

_reset() {
if (this._internalSubscription !== undefined) {
this._internalSubscription.unsubscribe()
}

static fromPromise<S>(promise: () => Promise<S>): AutoDisposeObservableProvider<S> {
return new AutoDisposeObservableProvider<S>(() => (from(promise()) as any))
this._valueSubject$ = new BehaviorSubject<T | undefined>(undefined)
this._errorSubject$ = new BehaviorSubject<T | undefined>(undefined)
}

_compute() {
this.ref = new AutoDisposeProviderReference(false)
this._reset()
this._observable$ = this.observableCreator(this.ref)
if (this._observable$ === null) {
throw 'observableCreator cannot return null. It must return an instance of Observable'
}

_compute() {
this.ref = new AutoDisposeProviderReference(false)
this._observable$ = this.observableCreator(this.ref)
if(this._observable$ === null) {
throw 'observableCreator cannot return null. It must return an instance of Observable'
this._internalSubscription = this._observable$.subscribe(
(val: T) => {
if (this.ref.executionError !== undefined) {
this._advanceError(this.ref.executionError)
return
}
this._internalSubscription = this._observable$.subscribe(
(val: T) => {
if(this.ref.executionError !== undefined) {
this._advanceError(this.ref.executionError)
return
}
this._advanceValue(val)
},
(error: any) => {
this._advanceError(error)
}
)
}
this._advanceValue(val)
},
(error: any) => {
this._advanceError(error)
}
)
}

_reset() {
if(this._internalSubscription !== undefined) {
this._internalSubscription.unsubscribe()
}
this._valueSubject$ = new BehaviorSubject(undefined)
this._errorSubject$ = new BehaviorSubject(undefined)
registerUnsubscribe() {
if (this.ref.maintainState === true) {
return
}

registerUnsubscribe() {
if(this.ref.maintainState === true) {
return
}
const valueObservers = this._valueSubject$.observers
const errorObservers = this._errorSubject$.observers
if(valueObservers.length < 1 && errorObservers.length < 1) {
this._reset()
}
const valueObservers = this._valueSubject$.observers
const errorObservers = this._errorSubject$.observers
if (valueObservers.length < 1 && errorObservers.length < 1) {
this._reset()
}
}
}
Loading

0 comments on commit 68d88d4

Please sign in to comment.