Skip to content

Instantly share code, notes, and snippets.

@nLight
Created May 9, 2014 18:01
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save nLight/0c6528e10abc37f9c0aa to your computer and use it in GitHub Desktop.
Save nLight/0c6528e10abc37f9c0aa to your computer and use it in GitHub Desktop.
Functional lenses in React.js with DrBoolean/lenses
<!DOCTYPE html>
<html>
<head>
<title>React JS Lenses</title>
<script src="react-with-addons.min.js"></script>
<script src="JSXTransformer.js"></script>
<!-- https://github.com/DrBoolean/lenses/blob/master/dist/lenses.browser.js -->
<script src="lenses.browser.js"></script>
<!-- https://github.com/DrBoolean/pointfree-fantasy/blob/master/dist/pointfree.browser.js -->
<script src="pointfree.browser.js"></script>
</head>
<body>
<script type="text/jsx">
/** @jsx React.DOM */
// 1. Passing a component specific piece of a state and let the component deal with it's internals
// 2. Giving a name to this piece of a state
// 3. React specific: it often unclear where one should put a state.
// With lenses we can put it in the root component or even outside of react
var Root = React.createClass({
getInitialState: function(){
return {
some: {
deep: [
{
structure: {
button: {label: "I'm very deep!"}
}
}
]
}
};
},
updateState: function(lens, value) {
// set returns a new copy state, so no mutation here
var newState = Lenses.set(lens, value, this.state);
console.log(newState, this.state);
this.setState(newState);
},
getState: function(lens) {
return Lenses.view(lens, this.state);
},
render: function(){
// Create lenses for our structure
// Order is not important here, these are granular lenses
var L = Lenses.makeLenses(['button', 'some', 'structure', 'deep', 'label']);
// Point to Button's piece of a state
// Simple composition:
// 1. get 'some' field of an Object
// 2. get 'deep' field of the result
// 3. get 0 element of the result
// ...
var deepLens = pointfree.compose(L.some, L.deep, L[0], L.structure, L.button);
// I heard you like lenses... Lenses are composable so we can compose a composition with other lenses :)
var deepLensLabel = pointfree.compose(deepLens, L.label);
// Instead of
// this.state.some.deep[0].structure.button.label
//
// We can use verbose name:
// Lenses.view(deepLensLabel, this.state)
return(
<div className="container">
<Button lens={deepLens}
viewLens={this.getState.bind(this)}
updateLens={this.updateState.bind(this)} />
<br/>
{this.state.some.deep[0].structure.button.label} == {Lenses.view(deepLensLabel, this.state)}
</div>
);
}
});
var Button = React.createClass({
handleClick: function (lens) {
this.props.updateLens(lens, 'Hello from the deep!');
},
render: function() {
var L = Lenses.makeLenses(['label']);
var labelLens = pointfree.compose(this.props.lens, L.label);
return (
<button onClick={this.handleClick.bind(this, labelLens)}>{this.props.viewLens(labelLens)}</button>
);
}
});
React.renderComponent(
<Root />,
document.body
);
</script>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment