Using npm:
$ npm i --save rxjs-hooks rxjs
Or yarn:
$ yarn add rxjs-hooks rxjs
importReactfrom"react";importReactDOMfrom"react-dom/client";import{useObservable}from"rxjs-hooks";import{interval}from"rxjs";import{map}from"rxjs/operators";functionApp(){constvalue=useObservable(()=>interval(500).pipe(map((val)=>val*3)));return(<divclassName="App"><h1>Incremental number: {value}</h1></div>);}importReactfrom"react";importReactDOMfrom"react-dom/client";import{useEventCallback}from"rxjs-hooks";import{map}from"rxjs/operators";functionApp(){const[clickCallback,[description,x,y]]=useEventCallback((event$)=>event$.pipe(map((event)=>[event.target.innerHTML,event.clientX,event.clientY]),),["nothing",0,0],)return(<divclassName="App"><h1>click position: {x}, {y}</h1><h1>"{description}" was clicked.</h1><buttononClick={clickCallback}>click me</button><buttononClick={clickCallback}>click you</button><buttononClick={clickCallback}>click him</button></div>);}exporttypeInputFactory<State>=(state$: Observable<State>)=>Observable<State>exporttypeInputFactoryWithInputs<State,Inputs>=(state$: Observable<State>,inputs$: Observable<RestrictArray<Inputs>>,)=>Observable<State>exportfunctionuseObservable<State>(inputFactory: InputFactory<State>): State|nullexportfunctionuseObservable<State>(inputFactory: InputFactory<State>,initialState: State): StateexportfunctionuseObservable<State,Inputs>(inputFactory: InputFactoryWithInputs<State,Inputs>,initialState: State,inputs: RestrictArray<Inputs>,): StateimportReactfrom'react'importReactDOMfrom'react-dom'import{useObservable}from'rxjs-hooks'import{of}from'rxjs'functionApp(){constvalue=useObservable(()=>of(1000))return(// render twice// null and 1000<h1>{value}</h1>)}With default value:
importReactfrom'react'importReactDOMfrom'react-dom'import{useObservable}from'rxjs-hooks'import{of}from'rxjs'functionApp(){constvalue=useObservable(()=>of(1000),200)return(// render twice// 200 and 1000<h1>{value}</h1>)}Observe props change:
importReactfrom'react'importReactDOMfrom'react-dom'import{useObservable}from'rxjs-hooks'import{map}from'rxjs/operators'functionApp(props: {foo: number}){constvalue=useObservable((_,inputs$)=>inputs$.pipe(map(([val])=>val+1),),200,[props.foo])return(// render three times// 200 and 1001 and 2001<h1>{value}</h1>)}constrootElement=document.querySelector("#app");ReactDOM.createRoot(rootElement).render(<Appfoo={1000}/>);ReactDOM.createRoot(rootElement).render(<Appfoo={2000}/>);useObservable with state$
importReactfrom'react'importReactDOMfrom'react-dom/client'import{useObservable}from'rxjs-hooks'import{interval}from'rxjs'import{map,withLatestFrom}from'rxjs/operators'functionApp(){constvalue=useObservable((state$)=>interval(1000).pipe(withLatestFrom(state$),map(([_num,state])=>state*state),),2)return(// 2// 4// 16// 256// ...<h1>{value}</h1>)}importReactfrom'react'importReactDOMfrom'react-dom'import{useEventCallback}from'rxjs-hooks'import{mapTo}from'rxjs/operators'functionApp(){const[clickCallback,value]=useEventCallback((event$: Observable<React.SyntheticEvent<HTMLButtonElement>>)=>event$.pipe(mapTo(1000)))return(// render null// click button// render 1000<><h1>{value}</h1><buttononClick={clickCallback}>click me</button></>)}With initial value:
importReactfrom'react'importReactDOMfrom'react-dom'import{useEventCallback}from'rxjs-hooks'import{mapTo}from'rxjs/operators'functionApp(){const[clickCallback,value]=useEventCallback((event$: Observable<React.SyntheticEvent<HTMLButtonElement>>)=>event$.pipe(mapTo(1000)),200,)return(// render 200// click button// render 1000<><h1>{value}</h1><buttononClick={clickCallback}>click me</button></>)}With state$:
importReactfrom"react";importReactDOMfrom"react-dom/client";import{useEventCallback}from"rxjs-hooks";import{map,withLatestFrom}from"rxjs/operators";functionApp(){const[clickCallback,[description,x,y,prevDescription]]=useEventCallback((event$,state$)=>event$.pipe(withLatestFrom(state$),map(([event,state])=>[event.target.innerHTML,event.clientX,event.clientY,state[0],])),["nothing",0,0,"nothing"]);return(<divclassName="App"><h1>
click position: {x}, {y}</h1><h1>"{description}" was clicked.</h1><h1>"{prevDescription}" was clicked previously.</h1><buttononClick={clickCallback}>click me</button><buttononClick={clickCallback}>click you</button><buttononClick={clickCallback}>click him</button></div>);}A complex example: useEventCallback with both inputs$ and state$
importReact,{useState}from"react";importReactDOMfrom"react-dom";import{useEventCallback}from"rxjs-hooks";import{map,withLatestFrom,combineLatest}from"rxjs/operators";import"./styles.css";functionApp(){const[count,setCount]=useState(0);const[clickCallback,[description,x,y,prevDesc]]=useEventCallback((event$,state$,inputs$)=>event$.pipe(map(event=>[event.target.innerHTML,event.clientX,event.clientY]),combineLatest(inputs$),withLatestFrom(state$),map(([eventAndInput,state])=>{const[[text,x,y],[count]]=eventAndInput;constprevDescription=state[0];return[text,x+count,y+count,prevDescription];})),["nothing",0,0,"nothing"],[count]);return(<divclassName="App"><h1>
click position: {x}, {y}</h1><h1>"{description}" was clicked.</h1><h1>"{prevDesc}" was clicked previously.</h1><buttononClick={clickCallback}>click me</button><buttononClick={clickCallback}>click you</button><buttononClick={clickCallback}>click him</button><div><p>
click buttons above, and then click this `+++` button, the position
numbers will grow.
</p><buttononClick={()=>setCount(count+1)}>+++</button></div></div>);}Example of combining callback observables coming from separate elements - animation with start/stop button and rate controllable via slider
constAnimation=({ frame })=>{constframes="|/-\\|/-\\|".split("");return(<div><p>{frames[frame%frames.length]}</p></div>);};constApp=()=>{constdefaultRate=5;const[running,setRunning]=useState(false);const[onEvent,frame]=useEventCallback(events$=>{construnning$=events$.pipe(filter(e=>e.type==="click"),scan(running=>!running,running),startWith(running),tap(setRunning));returnevents$.pipe(filter(e=>e.type==="change"),map(e=>parseInt(e.target.value,10)),startWith(defaultRate),switchMap(i=>timer(200,1000/i)),withLatestFrom(running$),filter(([_,running])=>running),scan(frame=>frame+1,0));});return(<divclassName="App"><buttononClick={onEvent}>{running ? "Stop" : "Start"}</button><inputtype="range"onChange={onEvent}defaultValue={defaultRate}min="1"max="10"></input><Animationframe={frame}/></div>);};If you are using React 18 + StrictMode under NODE_ENV=development, rxjs-hooks may not work properly. react/react#24502 (comment)