Skip to content

Instantly share code, notes, and snippets.

@seanhess
Last active August 29, 2015 14:16
Show Gist options
  • Save seanhess/e7322726b9a39c6fecf9 to your computer and use it in GitHub Desktop.
Save seanhess/e7322726b9a39c6fecf9 to your computer and use it in GitHub Desktop.
Cursor Proposal
const React = window.React = require('react')
const {map, append, partial, curry, compose} = require('ramda')
const shortid = require('shortid')
// STATE --------------------------------------------------------
// returns a state object, and automatically creates sub-cursors
// state.items = cursor to items
// state.items[0] = cursor to items[0].
const state = magicCursorFunction({
items: [
{id: 1, name: "one"},
{id: 2, name: "two"},
{id: 3, name: "three"}],
})
// API: CURSOR
// cursor.get()
// cursor.update(f)
// cursor.set(v)
// cursor.x = child cursor
// VIEW -----------------------------------------------------------
// each component gets passed a cursor that points to some js data
// call .get() to get the data, or .set() or .update() to trigger an update
const TodoItem = React.createClass({
render() {
const cursor = this.props.cursor
const item = cursor.get()
// note you can do cursor.name.get() instead of cursor.get().name
function onChange(e) {
cursor.update(setName(e.target.value))
// also works:
// cursor.name.set(e.target.value)
}
// other ways of writing the same thing
// I'm not sure it's helpful to create change functions like this
// it's probably always clearer to define a callback above
// maybe: cursor.makeUpdate()
const onChange2 = compose(cursor.update, setName, eventValue)
return <li>
<input value={item.name} onChange={onChange}/>
</li>
}
})
const TodoList = React.createClass({
render() {
const itemsCursor = this.props.cursor
const renderItem = i => <TodoItem cursor={i} key={i.id}/>
return <ul>
{map(renderItem, itemsCursor)}
</ul>
}
})
const TodoApp = React.createClass({
render() {
const cursor = this.props.cursor
const onAdd = () => cursor.update(addEmptyItem)
return <div className="row small-12 columns">
<h1>Items</h1>
<button onClick={onAdd}>Add Item</button>
<TodoList cursor={cursor} />
</div>
}
})
// I want to add items easily
const App = React.createClass({
render() {
return <TodoApp cursor={state.items}/> }
})
function render() {
React.render(
<App/>,
document.getElementById('content')
)
}
render()
state.onUpdate(render)
// HELPERS --------------------------------------------------------
// notice that none of these deal with cursors. They're all functions
// that just deal with data, and are immutable-style
const addItem = curry(function(item, items) {
return append(item, items)
})
const emptyItem = function() {
return {id: shortid.generate(), name: ""}
}
const addEmptyItem = compose(addItem, emptyItem)
const setName = curry(function(value, item) {
item.name = value
return item
})
const eventValue = function(e) {
return e.target.value
}
@mrmurphy
Copy link

mrmurphy commented Mar 4, 2015

So this is a strawman of what the api will look like? I like it. How do you keep the cursor up to date? does the state update its items attribute to be a refreshed cursor whenever the underlying structure is changed?

@seanhess
Copy link
Author

seanhess commented Mar 4, 2015

@murphyrandle yep, great! It's kept up to date the same way as omniscient, the component should get refreshed every time it's updated. I haven't implemented anything yet, so I don't have details, but the basic idea is that a cursor is just an addressing function into the data and a reference to the current data.

@mrmurphy
Copy link

mrmurphy commented Mar 4, 2015

Okay cool. As far as the api goes I think it looks good. @numso and I worked out a potential alternative last night as well, and he implemented a test today. I'd like for him to post that up so that we can all comment on it also.

Btw, I decided not to vet the idea I brought up earlier about pouchdb. I don't really want us to do that. :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment