-
-
Save maksadbek/91464258b8d50ad87757cdb80c980323 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// A quick experiment with Channels and React | |
// this needs more thinking | |
// but might be useful as a starting point. | |
import React from 'react' | |
import { render } from 'react-dom' | |
import { chan, go, timeout, take, put, putAsync, buffers } from 'js-csp'; | |
import { add, assoc, curry, compose, map, mapObjIndexed, max, pluck, prop, reduce } from 'ramda' | |
const initialState = { | |
items: [], | |
isLoading: false, | |
} | |
let createStore = function(state) { | |
let _state = state | |
return { | |
get: () => _state, | |
set: state => { | |
_state = state | |
} | |
} | |
} | |
// helper | |
const createRender = curry((node, app) => render(app, node)) | |
// create App channel... and render function | |
const AppChannel = chan(buffers.sliding(1)) | |
const doRender = createRender(document.getElementById('mountNode')) | |
const store = createStore(initialState) | |
function* fetchItems(query) { | |
yield timeout(2000) | |
return [{id: 1, title: 'foo'}, {id: 2, title: 'bar'}] | |
} | |
const createChannel = (action, store) => { | |
const ch = chan() | |
go(function* () { | |
while(true) { | |
const value = yield take(ch) | |
yield put(AppChannel, action(store.get(), value)); | |
} | |
}) | |
return ch | |
} | |
// helper function for passing an object and getting channels | |
const createChannels = (actions, store) => | |
mapObjIndexed(fn => createChannel(fn, store), actions) | |
// channels... | |
const getItems = () => { | |
go(function* () { | |
yield put(isLoading, true) | |
const fetchedItems = yield* fetchItems() | |
yield put(items, fetchedItems) | |
yield timeout(10) | |
yield put(isLoading, false) | |
}) | |
} | |
const getNextId = compose(add(1), reduce(max, 0), pluck('id')) | |
const Actions = { | |
isLoading: (model, isLoading) => assoc('isLoading', isLoading, model), | |
items: (model, items) => assoc('items', items, model), | |
addItem: (model, title) => | |
assoc('items', | |
[ ...prop('items', model), {title, id: getNextId(prop('items', model))} ], | |
model), | |
} | |
const { isLoading, items, addItem } = createChannels(Actions, store) | |
const findText = () => { | |
const textEl = document.getElementById('add') | |
const val = textEl.value | |
textEl.value = '' | |
return val | |
} | |
const App = ({ items, isLoading }) => { | |
if (isLoading) return (<p>loading...</p>) | |
return ( | |
<div> | |
<h2>Random Items List</h2> | |
<ul> | |
{items.map(item => ( | |
<li key={item.id} >{item.title}</li> | |
))} | |
</ul> | |
<input type='text' id='add' /> | |
<button onClick={() => putAsync(addItem, findText())}>Add Item</button> | |
<button onClick={() => getItems()}>LoadItems</button> | |
</div> | |
) | |
} | |
const AppStart = (Component, store) => { | |
// initial render... | |
putAsync(AppChannel, store.get()) | |
go(function* () { | |
while(true) { | |
store.set(yield take(AppChannel)) | |
doRender(<Component {...store.get() } />) | |
} | |
}) | |
} | |
// start | |
AppStart(App, store) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment