https://github.com/helmutkian/cl-react
Common Lisp (Parenscript) utilities for building web apps in ReactJs
https://github.com/helmutkian/cl-react
Last synced: 3 months ago
JSON representation
Common Lisp (Parenscript) utilities for building web apps in ReactJs
- Host: GitHub
- URL: https://github.com/helmutkian/cl-react
- Owner: helmutkian
- License: mit
- Created: 2015-06-07T21:31:30.000Z (almost 11 years ago)
- Default Branch: master
- Last Pushed: 2020-11-21T18:51:05.000Z (over 5 years ago)
- Last Synced: 2025-03-20T15:40:15.764Z (about 1 year ago)
- Language: Common Lisp
- Size: 83 KB
- Stars: 69
- Watchers: 11
- Forks: 2
- Open Issues: 4
-
Metadata Files:
- Readme: README.md
- License: LICENSE.txt
Awesome Lists containing this project
- awesome-cl - cl-react - Common Lisp (Parenscript) utilities for building web apps in ReactJs. MIT. (Interfaces to other package managers / Isomorphic web frameworks)
README
# cl-react
Common Lisp (Parenscript) utilities for building web apps in ReactJs
### Installation
* Clone the repo ``git clone https://github.com/helmutkian/cl-react.git``
* Fire up your Common Lisp environment
* Load the ASDF system definition ``(load ")``
* Load the system ``(ql:quickload 'cl-react)``
* Build the JavaScript library ``(cl-react:build)``
### PSX
PSX is a Parenscript equivilent to JSX, ReactJs's extended JavaScript syntax. It uses the familiar CL-WHO syntax for markup generation.
````common-lisp
(ps:ps
(cl-react:psx
(:a :href (cl-react:with-ps (ps:@ this props site-url))
(:span :class "text-green" (cl-react:with-ps (ps:@ this props site-name))))))
````
=>
````javascript
React.DOM.a({ href: this.props.siteUrl }, [
React.DOM.span({ className: 'text-green' }, this.props.siteName)
]);
````
### Convenience Functions / Macros
CL-React contains some convenience aliases for commonly used React functions:
Lisp functionReact original
create-classReact.createClass
create-elementReact.createElement
create-factoryReact.createFactory
unmount-component-at-nodeReact.unmountComponentAtNode
is-valid-elementReact.isValidElement
find-dom-nodeReact.findDOMNode
renderReactDOM.render
render-to-stringReact.renderToString
render-to-static-markupReact.renderToStaticMarkup
children-mapReact.Children.map
children-countReact.Children.count
children-onlyReact.Children.only
(prop item)this.props.item
(state item)this.state.item
(set-state item value)this.setState(item, value)
####Def-component
The def-component macro is a wrapper around create-class.
A typical create-class might look like this:
````common-lisp
(var sample-component
(create-class
(create
get-initial-state
(lambda () ...)
render
(lambda () )
...)))
````
Def-component tightens it up to this:
````common-lisp
(def-component sample-component
get-initial-state
(lambda () ...)
...)
````
The body of the def-component macro is implicitly wrapped in a (create ...) call that, with the exception of the first item, must contain key/value pairs. The first body item will be automatically paired with the render key and enclosed in a lambda expression.
A nil in the name parameter will cause def-component to return a class without attempting to save it.
To skip the implicit render body - for example, when supplying an external render function - place nil as the first item in the body.
###Example code
Below is an example based on the [React tutorial](https://facebook.github.io/react/docs/tutorial.html). The javascript version is followed by the equivalent in parenscript/cl-react.
````javascript
var data = [
{id: 1, author: "Pete Hunt", text: "This is one comment"},
{id: 2, author: "Jordan Walke", text: "This is *another* comment"}
];
var CommentForm = React.createClass({
render: function() {
return (
Hello, world! I am a CommentForm.
);
}
});
var Comment = React.createClass({
rawMarkup: function() {
var rawMarkup = marked(this.props.children.toString(), {sanitize: true});
return { __html: rawMarkup };
},
render: function() {
return (
{this.props.author}
);
}
});
var CommentList = React.createClass({
render: function() {
var commentNodes = this.props.data.map(function(comment) {
return (
{comment.text}
);
});
return (
{commentNodes}
);
}
});
var CommentBox = React.createClass({
render: function() {
return (
Comments
);
}
});
ReactDOM.render(
,
document.getElementById('content')
);
````
````common-lisp
(var data
(list
(create id 1 author "Peter Hunt" text "This is one comment")
(create id 2 author "Jordan Walke" text "This is *another* comment")))
(def-component -comment-form
(psx (:div :class-name "commentForm" "Hello, world! I am a CommentForm")))
(def-component -comment
(psx
(:div :class-name "comment"
(:h2 :class-name "commentAuthor" (prop author))
(:span :dangerously-set-inner-h-t-m-l (chain this (raw-markup)))))
raw-markup
(lambda ()
(create __html (marked (prop children (to-string)) (create sanitize t)))))
(def-component -comment-list
(let ((comment-nodes
(mapcar
(lambda (comment)
(psx (:-comment :author (@ comment author) :key (@ comment id)
(@ comment text))))
(prop data))))
(psx (:div :class-name "commentList" comment-nodes))))
(def-component -comment-box
(psx (:div :class-name "commentBox"
(:h1 "Comments")
(:-comment-list :data (prop data))
(:-comment-form))))
(render (psx (:-comment-box :data data))
(chain document (get-element-by-id "content")))
````