/* model.js */ // static workflow export const changeInput = declareAction() export const inputAtom = declareAtom('', on => [ on(changeInput, (_, input) => input), ]) // lifetime workflow export const init = declareAction(store => { const ws = new Socket(url) const initInput = store.getState(inputAtom) ws.on('@init', input => { if (store.getState(inputAtom) === initInput) store.dispatch(changeInput(input)) }) const unsubscribe = store.subscribe(inputAtom, input => ws.send('input', input), ) store.subscribe(cleanup, () => { ws.disconnect() unsubscribe() }) }) export const cleanup = declareAction() /* view.js */ const onInit = useAction(init) const onCleanup = useAction(cleanup) useEffect(() => { onInit() return () => onCleanup() }, [])