Fork me on GitHub

ReactJS tutorial in ki

The index.html page:

<html>
  <head>
    <title>Hello React</title>
    <script src="http://fb.me/react-0.8.0.js"></script>
    <script src="http://code.jquery.com/jquery-1.10.0.min.js"></script>
    <script src="mori.js"></script>
  </head>
  <body>
    <div id="content"></div>
    <script src="react_ki.out.js"></script>
  </body>
</html>

A few macros for writing React components concisely using s-expressions instead of JSX

ki macro (defcomp $name $render_body) 
         (def $name ((js React.createClass) 
                     {$ 'render' (fn [] $render_body)}))
                     
ki macro (defcomp $name {$kv ...} $render_body) 
         (def $name ((js React.createClass) 
                     {$kv ... 'render' (fn [] $render_body)}))
                                         
ki macro (dom $tag {$kv ...} $children ...)
         ((js React.DOM.$tag) {$kv ...} $children ...)
                                                   
ki macro (dom $tag $children ...)
         ((js React.DOM.$tag) (js {}) $children ...)

Tutorial code starts here. A few things to note:

In a more elaborate version global state could be moved to an atom using atom callbacks to trigger a re-rendering.

ki require core

ki (do

 (def data [{:author "Pete Hunt" :text "This is one comment"}
            {:author "Jordan Walke" :text "This is another comment"}])

 (defcomp Comment
  (dom div {$ :className 'comment'} 
   (dom h2 {$ :className 'commentAuthor'} this.props.author) 
   this.props.children))

 (defcomp CommentList
  (dom div {$ :className 'commentList'} 
   (toJs 
    (map (fn [comment i] 
          (Comment {$ :author (get comment :author)} (get comment :text))) 
     this.props.data))))

 (defcomp CommentForm
  {$ :handleSubmit 
      (fn []
       (let [author (js this.refs.author.getDOMNode().value.trim())
             text (js this.refs.text.getDOMNode().value.trim())]
        (this.props.onCommentSubmit {:author author :text text})
        (js this.refs.author.getDOMNode().value = '')
        (js this.refs.text.getDOMNode().value = '')
        false))}
  (dom form {$ :className 'commentForm' :onSubmit this.handleSubmit} 
   (dom input {$ :type 'text' :placeholder 'Your name' :ref 'author'})
   (dom input {$ :type 'text' :placeholder 'Say something...' :ref 'text'})
   (dom input {$ :type 'submit' :value 'Post'})))

 (defcomp CommentBox 
  {$ :getInitialState
      (fn [] 
       {$ :data [{:author "Pete Hunt" :text "This is one comment"}]})
     :componentWillMount 
      (fn [] 
       (setTimeout (fnth [] (this.setState {$ :data data})) 1000))
     :handleCommentSubmit 
      (fn [comment] 
       (this.setState {$ data (conj this.state.data comment)}))}
  (dom div {$ :className 'commentBox'} 
   (dom h1 'Comments') 
   (CommentList {$ :data this.state.data}) 
   (CommentForm {$ :onCommentSubmit this.handleCommentSubmit})))

 (React.renderComponent (CommentBox) (document.getElementById 'content'))
)