Skip to content

Commit

Permalink
feat: add selector for useObservableCallback
Browse files Browse the repository at this point in the history
  • Loading branch information
crimx committed Aug 31, 2019
1 parent 6383b68 commit af30f0c
Show file tree
Hide file tree
Showing 2 changed files with 53 additions and 5 deletions.
39 changes: 34 additions & 5 deletions src/use-observable-callback.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@ import { useRefFn, getEmptySubject } from './helpers'
* Whenever the callback is called, the Observable will
* emit the first argument of the callback.
*
* (From v2.1.0) Optionally accepts a selector function that transforms
* a list of event arguments into a single value.
*
* If you need a value instead of an Observable,
* see example on [[useObservableState]].
*
Expand All @@ -29,14 +32,40 @@ import { useRefFn, getEmptySubject } from './helpers'
* return <input type="text" onChange={onChange} />
* }
* ```
*
* Transform event arguments:
*
* ```typescript
* import { useObservableCallback, identity } from 'observable-hooks'
*
* const [onResize, height$] = useObservableCallback<
* number,
* number,
* [number, number]
* >(identity, args => args[1])
*
* // onResize is called with width and hegiht
* // height$ gets height values
* onResize(100, 500)
* ```
*
* @param init A function that, when applied to an inputs Observable,
* returns an Observable.
* @param selector A function that transforms a list of event arguments
* into a single value.
*/
export function useObservableCallback<Output, Event = Output>(
init: (events$: Subject<Event>) => Observable<Output>
): [(e: Event) => void, Observable<Output>] {
export function useObservableCallback<
Output,
Event = Output,
Args extends any[] = [Event]
>(
init: (events$: Observable<Event>) => Observable<Output>,
selector?: (args: Args) => Event
): [(...args: Args) => void, Observable<Output>] {
const events$Ref = useRefFn<Subject<Event>>(getEmptySubject)
const outputs$Ref = useRefFn(() => init(events$Ref.current))
const callbackRef = useRef((e: Event) => {
events$Ref.current.next(e)
const callbackRef = useRef((...args: Args) => {
events$Ref.current.next(selector ? selector(args) : args[0])
})
return [callbackRef.current, outputs$Ref.current]
}
19 changes: 19 additions & 0 deletions test/use-observable-callback.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,4 +35,23 @@ describe('useObservableCallback', () => {
expect(spy).toBeCalledTimes(2)
expect(spy).lastCalledWith('world')
})

it('should get the selected argument from selector', () => {
const { result } = renderHook(() =>
useObservableCallback<string, string, [boolean, string]>(
identity,
args => args[1]
)
)
const [onChange, event$] = result.current
const spy = jest.fn()
event$.subscribe(spy)
expect(spy).toBeCalledTimes(0)
onChange(true, 'hello')
expect(spy).toBeCalledTimes(1)
expect(spy).lastCalledWith('hello')
onChange(false, 'world')
expect(spy).toBeCalledTimes(2)
expect(spy).lastCalledWith('world')
})
})

0 comments on commit af30f0c

Please sign in to comment.