Skip to content

Commit

Permalink
[react-hooks] Refactor useUser hook to return loadable values
Browse files Browse the repository at this point in the history
  • Loading branch information
rexxars committed Oct 6, 2020
1 parent ed085b4 commit 706faf9
Show file tree
Hide file tree
Showing 3 changed files with 72 additions and 6 deletions.
2 changes: 1 addition & 1 deletion packages/@sanity/react-hooks/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,4 @@ export {useValidationStatus} from './useValidationStatus'
export {useSyncState} from './useSyncState'
export {useConnectionState} from './useConnectionState'
export {useDocumentOperationEvent} from './useDocumentOperationEvent'
export {useUser, LOADING_USER} from './useUser'
export {useUser} from './useUser'
8 changes: 3 additions & 5 deletions packages/@sanity/react-hooks/src/useUser.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,12 @@
import userStore from 'part:@sanity/base/user'
import {useObservable} from './utils/use-observable'
import {useLoadable, LoadableState} from './utils/useLoadable'

export interface User {
id: string
displayName?: string
imageUrl?: string
}

export const LOADING_USER = Symbol.for('LOADING_USER')

export function useUser(userId): User | null | typeof LOADING_USER {
return useObservable(userStore.observable.getUser(userId))
export function useUser(userId): LoadableState<User> {
return useLoadable(userStore.observable.getUser(userId))
}
68 changes: 68 additions & 0 deletions packages/@sanity/react-hooks/src/utils/useLoadable.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
import * as React from 'react'
import {Observable, Subscription} from 'rxjs'

export type LoadableState<T> = LoadingState<T> | LoadedState<T> | ErrorState<T>

export interface LoadingState<T> {
value: undefined
error: undefined
isLoading: true
}

export interface LoadedState<T> {
value: T
error: undefined
isLoading: false
}

export interface ErrorState<T> {
value: undefined
error: Error
isLoading: false
}

export function useLoadable<T>(observable$: Observable<T>): LoadableState<T>
export function useLoadable<T>(observable$: Observable<T>, initialValue: T): LoadableState<T>
export function useLoadable<T>(observable$: Observable<T>, initialValue?: T): LoadableState<T> {
const subscription = React.useRef<Subscription>()
const [value, setState] = React.useState<LoadableState<T>>(() => {
let isSync = true
let syncVal: LoadableState<T> =
typeof initialValue === 'undefined'
? {isLoading: true, value: undefined, error: undefined}
: {isLoading: false, value: initialValue, error: undefined}

subscription.current = observable$.subscribe(
nextVal => {
const nextState: LoadedState<T> = {
isLoading: false,
value: nextVal,
error: undefined
}

if (isSync) {
syncVal = nextState
} else {
setState(nextState)
}
},
error => {
setState({isLoading: false, error, value: undefined})
}
)

isSync = false
return syncVal
})

React.useEffect(
() => () => {
if (subscription.current) {
subscription.current.unsubscribe()
}
},
[]
)

return value
}

0 comments on commit 706faf9

Please sign in to comment.