import React, { useEffect, useState, useCallback } from 'react'; | |
import { render } from 'react-dom'; | |
import { run } from 'frap'; | |
import xs, { Stream } from 'xstream'; | |
import { useStream } from './util'; | |
import { State, View, startState } from './main.ts'; | |
/** Our 'send' function signature. */ | |
type Send = (event: View) => void; | |
const App = () => { | |
const [state$, setState] = useState<Stream<State>>(xs.empty()); | |
const view$ = xs.create<View>(); | |
// Create our actual 'send' function which drives the view$ | |
// stream, which goes into `main`. | |
const send: Send = useCallback((v: View) => { | |
view$.shamefullySendNext(v); | |
}, []); | |
useEffect(() => { | |
// After mounting, kick the whole app off 🎉 | |
const state$ = run(view$); | |
setState(state$); | |
}, []); | |
// 'state' now includes our whole app state as a plain object | |
const state = useStream(state$, startState); | |
return ( | |
<div> | |
<h1>Hi {state.name}!</h1> | |
<button onClick={() => send({ | |
kind: 'set_name', | |
name: 'Johnny Doe', | |
})}>Set to another</button> | |
</div> | |
); | |
}; | |
render(<App />, document.getElementById('app')); |
import { useEffect, useState } from 'react'; | |
import { Stream } from 'xstream'; | |
export const isKind = <T>(kind: string) => | |
(t: any): t is T => t.kind === kind; | |
/** | |
* Hook for using xstream streams in React components. | |
* | |
* Usage: | |
* ```ts | |
* const theString = useStream<string>(someStringStream$, 'start'); | |
* console.log(theString); // logs values for someStringStream$ | |
``` | |
*/ | |
export const useStream = <T>(stream$: Stream<T>, initialState: T) => { | |
const [current, setCurrent] = useState<T>(initialState); | |
useEffect(() => { | |
const sub = stream$.subscribe({ | |
next: setCurrent, | |
}); | |
return () => sub.unsubscribe(); | |
}); | |
return current; | |
}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment