JSFiddle - React, Tailwind, and code Playground
by Dustin Getz
HTML
<script src="http://fb.me/react-with-addons-0.9.0.js"></script>
<script src="http://fb.me/JSXTransformer-0.9.0.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/underscore.js/1.5.2/underscore.js"></script>
<script src="http://fb.me/react-js-fiddle-integration.js"></script>
JavaScript 1.7
/** @jsx React.DOM */
var App = React.createClass({
getInitialState: function () {
return {
count: 0
};
},
render: function() {
var cursor = Cursor.build(this.state, this.setState.bind(this), cloneDeep);
return this.transferPropsTo(<Clicker cursor={cursor}/>);
}
});
var Clicker = React.createClass({
render: function () {
return (
<div>
<span>{this.props.cursor.refine('count').value}</span>
<button onClick={this.inc2}>+2</button>
</div>
);
},
inc2: function () {
var countCursor = this.props.cursor.refine('count');
countCursor = countCursor.onChange(countCursor.value + 1);
countCursor = countCursor.onChange(countCursor.value + 1);
}
});
// this constructor is private
function Cursor(state, path, commit, clone) {
state = clone(state); // defensive clone right away so we can't close over a stale state reference
this.value = getRefAtPath(state, path);
this.onChange = function (nextValue) {
var nextState;
nextValue = clone(nextValue); // because the call site might retain the reference and mutate
if (path.length > 0) {
nextState = state;
var scoped = getRefAtPath(nextState, initial(path));
scoped[last(path)] = nextValue;
}
else if (path.length === 0) {
nextState = nextValue;
}
commit(nextState);
return new Cursor(nextState, path, commit, clone);
};
this.refine = function (/* one or more paths through the tree */) {
var nextPath = [].concat(path, flatten(arguments));
return new Cursor(state, nextPath, commit, clone);
};
}
/**
* Example usages:
* Cursor.build(this.state, this.setState.bind(this), _.cloneDeep);
*...