
React-cursor: a JavaScript implementation of the Cursor concept first seen in Om - dustingetz
https://github.com/dustingetz/react-cursor/
======
dustingetz
(Author here) I have added a short section to the readme describing how
`react-cursor` differs from other, similar, libraries (e.g. Cortex).
[https://github.com/dustingetz/react-cursor#comparisons-to-
si...](https://github.com/dustingetz/react-cursor#comparisons-to-similar-
libraries)

~~~
mattdeboard
The comment on the double setState issue on Github just cleared up a point of
confusion for me:

> It might be best to think of setState as being enqueueStateUpdate

Is this why the cursor objects have something like a "pendingState" property?
I can't remember the exact name, just that it exists.

~~~
dustingetz
That is correct. `cursor.value` always respects the react component lifecycle:
this is what you always want in `render()`, `componentWillUpdate()` and other
React lifecycle methods.

`cursor.pendingValue()` gives you the latest queued state update, which is
always what you want in your event handlers (e.g. complicated state
transitions in response to a click).

The decision is essential complexity, but at least when you use cursors the
decision is mechanical. React has a slightly different API (but equivalent
information) that makes the decision less mechanical.

------
j_s
If you are tired of using callbacks when nesting data structures with React,
be sure to check out Cortex:
[https://github.com/mquan/cortex](https://github.com/mquan/cortex)

 _Cortex 's goal is to support arbitrarily deep data structure without
requiring you to pass callbacks down the chain._

~~~
mattdeboard
What I need is something like this that abstracts away where data is coming
from (i.e. facade pattern). This would help make implementing offline
capability seamless, and a discrete concern from the UI.

~~~
binarymax
Indeed. I spent a bunch of time looking for something like that which already
exists, but couldn't find anything and have resigned to building it myself.
When it gets to a better state I'll be releasing it. Probably in a week or so.

~~~
nwienert
+1 on being interested... I'm beginning the same journey here:
[https://github.com/natew/testreactor](https://github.com/natew/testreactor)

------
jimmyhmiller
This looks really nice. I'm actually really happy to see the json editor, been
thinking about including something along those lines for debugging/interactive
discovery in my react apps.

One thing I'm a little confused about is the onChange method. Is that supposed
to be like Om's transact? If so, that seems like an unfortunate name. onChange
sounds like a callback, not a way to create a new state.

~~~
dustingetz
The most common use of cursors will eventually bind them to React form
components. Cursor's value/onChange interface is meant to directly line up
with React form components' value/onChange convention. That said, I get asked
this question a lot, perhaps mostly by people who aren't already React
developers.

~~~
ericflo
Coming from someone who has used React.js a lot, I found the name unintuitive
as well. Would've expected a variant on setState. That said, this library
looks extremely useful and I can't wait to try it out in a project -- thanks
for publishing it!

------
ville
Facebook's Immutable also provides Cursors for its immutable collections:
[https://github.com/facebook/immutable-
js#cursors](https://github.com/facebook/immutable-js#cursors)

~~~
skrebbel
I found immutable-js's cursors to be rather limited for use with react. Using
them is very verbose, and you often end up nesting 2 or 3 little anonymous
functions when doing mutations.

I ended up hacking my own version of the same idea, but with an explicit
reference to a mutable data slot, much like the cursors in this post do.

I use a lot of Immutable.Record for domain objects, and I found that I could
get nicely succinct code by adding a getter property to the cursor for each
field in a record. It yields a new cursor if the value is an immutable
collection too, or else the actual value the cursor points to. This seems like
a weird heuristic until you realize that most programming languages make the
same distinction (primitive values are cloned, object references are not).

This allows me to write code like

    
    
        <span>{this.props.user.group.name}</span>
    

Where this.props.user is a _cursor_ , not an immutable collection. This is
cool, because I only pass around subcursors around my component tree, but I
can address them as if they're the values themselves when rendering. And I can
still mutate them as a cursor.

I didn't publish this code, or even evaluate the performance of it, but if
anyone cares I don't mind sharing.

~~~
dustingetz
(Author here) I explored an API like that, the problem I ran into was that
often you don't want to refine all the way to a primitive; e.g. What is the
value of the whole record so I can validate it? Sometimes you want the record,
sometimes you want the cursor.

~~~
skrebbel
I noticed that you probably always want the value if the value is a leaf of
the tree (typically a primitive value). Similarly, for validation, do you
validate records of the values _on_ the records? If the syntax to access the
values via a record cursor or via a record is exactly the same, then you can
just pass the cursor to the validation function, rather than the record. The
validation function doesn't even need to know that it got a cursor.

I'm curious whether you could shoot any holes in that reasoning.

------
kylecordes
This sounds snarky, but I mean it earnestly. Rather than move from JS to
ClojureScript one library at a time, why not step all at once? I think by the
time you use a bunch of libraries this way, you will be almost as far from
common JS practice as you would just using CLJS in the first place.

~~~
nwienert
I could think of a few reasons why not. Learning curve being a big one. For
startups it's the difference in finding developers. Preference could be
another, whether you think imperative code to be more readable, or maybe you
enjoy classes or other JS-targeting languages.

I've looked into Om/ClojureScript now a few times and the learning curve is
steep and keeps putting me off, but also I fear that if I start a project with
it I'll alienate potential future devs and have difficulty gaining traction.
Plus, with ES6/CoffeeScript/TypeScript and libraries like this it's more
possible than ever to build a beautiful environment to code in that doesn't
require such a big jump.

But hey, at least this stuff brings more exposure to ClojureScript. That's
definitely a good sign.

~~~
undershirt
Clojurescript might be more of a magnet than a filter in finding developers. I
think any developer would be excited to learn the language that influenced
React and the immutable js libraries... as long as they had some guidance and
employment to do it!

In my experience, I joined a company specifically to learn/use clojurescript
and others joined the same time, and we were committing code after 2 weeks.

Om has a steep learning curve. I'd recommend quiescent if you want the bare
minimum for interfacing with React in cljs.

------
kyberias
I'm confused. Is there a tutorial or book that explains all the (modern)
Javascript software design concepts mentioned in this readme?

~~~
dustingetz
If its the functional programming jargon you're interested in, you might start
with Javascript Allonge [1]

[1] [https://leanpub.com/javascript-
allonge/read](https://leanpub.com/javascript-allonge/read)

~~~
acjohnson55
I highly recommend this book as well, although it would probably be of limited
help with the concepts in this project. I'd suggest reading more about React,
the Om project, and immutable data structures to get some background.

------
worldsayshi
As someone who has been building on a react gui for some time I can see how
this could take away some of the worst boilerplate that remains - in the form
of callbacks calling callbacks. Exiting! But it seems it doesn't go all the
way. I imagine I still need to do some boilerplating. I don't directly see how
that would be avoided though.

------
undershirt
In Om, you can't create Cursors to primitive values. Rather, you can only
create Cursors to indexable collections, like a Map or Vector. Looks like
React-Cursor allows this, so I'll take another look to see what's preventing
this in Om.

~~~
swannodette
You can create cursor on primitives in Om, it's just a can of worms as it
makes clear the dichotomy between native value & Object versions of those
values.

------
cliftonk
Also see
[https://github.com/caseywebdev/cursors](https://github.com/caseywebdev/cursors)

~~~
caseywebdev
I went for a minimalist implementation that leverages the work done in React's
Immutability Helpers
([http://facebook.github.io/react/docs/update.html](http://facebook.github.io/react/docs/update.html)).
The API allows you to use the same `this.state.xxx` you're used to which I
find nice.

------
polskibus
How do I use the cursor to build a recursive json editor that allows appending
the tree? Does onChange support adding new elements to the cursor or can I
only operate on elements that have been previously fed to the cursor?

~~~
dustingetz
if your state is { foo: ['a','b','c'] }, you can either do:

    
    
        cursor.refine('foo', 3).onChange('d')
        cursor.refine('foo').onChange(['a', 'b', 'c', 'd'])
    

(indexes in a js array are the same as keys in a map)

It is possible to implement `push` and other list/object ops that are exposed
by React.addons.update, they have not been implemented yet because they make
the interface more complicated.

[http://facebook.github.io/react/docs/update.html](http://facebook.github.io/react/docs/update.html)

I opened an issue for discussion: [https://github.com/dustingetz/react-
cursor/issues/10](https://github.com/dustingetz/react-cursor/issues/10)

~~~
polskibus
Thanks, I was more wondering whether I can have something like :

    
    
      cursor.refine('foo').onChange({'child':{}});
    

in one place and then in some other, code that would dwelve inside that child
recursively (and append the "add child" action to that node as well)

My goal is to have a json editor with json as the only model in the
application and have react/cursor automatically render the tree, and allow its
modification (removing and adding nodes).

Such functionality would require cursor to "dive" inside a json node without
knowing its name - I'm not sure whether the 'push' op you are mentioning would
be required to achieve this.

------
nickik
This might be of topic, but is there a clojure edn visualiser/editor that
works like that json editor?

~~~
undershirt
Give ankha a try. It's still in early development:
[https://github.com/noprompt/ankha](https://github.com/noprompt/ankha)

------
niix
Man I really need to learn React.js, this stuff is just getting more and more
interesting by the day.

~~~
koistya
This project template can be useful when playing with React.js

[https://github.com/kriasoft/react-starter-
kit](https://github.com/kriasoft/react-starter-kit)

------
jchrisa
My guess is this can get really slick when we have ES6 Proxy capabilities.

------
colinramsay
Am being I slow? I can't see the source code to the JSON editor.

~~~
dubcanada
Try [http://react-json-editor.bitballoon.com/examples/react-
state...](http://react-json-editor.bitballoon.com/examples/react-state-
editor/webapp/)

------
smrtinsert
iirc doesn't Reagent do this automatically via caching?

