LoginSignup
2
1

More than 5 years have passed since last update.

A (extremely) shallow comparison between React/JS and Om/CLJS usage

Last updated at Posted at 2015-01-23

The purpose of this article is just to show some really basic differences between using React with Javascript and using Om with Clojurescript. There are, of course, better ways to do what I'm going to show here, so please comment and suggest corrections as you see fit (here or twitter).

At the end of the day, your team/organization should probably weigh the benefits and the costs of using one or the other.

Basic Component Definition

Keep in mind that in CLJS/Om, you can take advantage of immutable data structures to get pure rendering out of the box, so there won't be wasted rendering (if you scope props correctly). With JS/React, you'll have to add PureRenderMixin or something to achieve the same and be disciplined in how you modify state. See my other boring post about this: http://qiita.com/kimagure/items/c38444713ea48a6f02e8 (or go straight to the demo: http://jsbin.com/cobiyi/1/edit?js,output)

Application state and root

var appState = {
  columns: [{
    id: 'name',
    title: "Name"
  }, {
    id: 'episode',
    title: "Episode"
  }, {
    id: 'lastViewed',
    title: "Last Viewed"
  }],
  rows: [{
    id: 1,
    name: 'dfsds',
    episode: 1,
    lastViewed: "20-Jan-14"
  }, {
    id: 2,
    name: "sdfsdfsd",
    episode: 2,
    lastViewed: "21-Jan-14"
  }, {
    id: 3,
    name: "vcxvcsd",
    episode: 5,
    lastViewed: "14-Jan-14"
  }]
};

function renderApp(state) {
  React.render(<TrackerTable appState={state}/>, document.getElementById('app'));
}
(def app-state
  (atom
    {:columns [{:id :name :title "Name"}
               {:id :episode :title "Episode"}
               {:id :last-viewed :title "Last Viewed"}]
     :rows [{:id 1 :name "dfsds" :episode 1 :last-viewed "20-Jan-14"}
            {:id 2 :name "sdfsdfsd" :episode 2 :last-viewed "21-Jan-14"}
            {:id 3 :name "vcxvcsd" :episode 5 :last-viewed "14-Jan-14"}]}))

(om/root
  (fn [app owner]
    (reify om/IRender
      (render [_]
        (om/build tracker-table app))))
  app-state
  {:target (. js/document (getElementById "app"))})

Main table

JS version calls React.createClass and passes in an object, uses JSX that is transformed to plain JS targeting the specific methods per version of React.

var TrackerTable = React.createClass({
  render: function () {
    var columns = this.props.columns;
    var rows = this.props.rows;
    return (
      <table>
        <TrackerHeader columns={columns}/>
        <TrackerBody columns={columns} rows={rows}/>
      </table>
    );
  }
});

CLJS version defines a function that implements om/IRender.

(defn tracker-table [props]
  "my tracker table"
  (reify om/IRender
    (render [_]
      (dom/table
        #js {}
        (om/build tracker-header (:columns props))
        (om/build tracker-body props)))))

Table row

These two do the same thing.

// var PureRenderMixin = require('react/lib/ReactComponentWithPureRenderMixin');
var TrackerRow = React.createClass({
  // mixins: [PureRenderMixin],
  render: function () {
    var row = this.props.row;
    var columns = this.props.columns.map(function (column) {
      var id = column.id;
      return (
        <td key={id}>
          {row[id]}
        </td>
      );
    });
    return (
      <tr>
        {columns}
      </tr>
    );
  }
});
(defn tracker-row [props]
  "my tracker row"
  (let [{columns :columns row :row} props]
    (reify om/IRender
      (render [_]
        (apply
          dom/tr
          #js {:key (:id row)}
          (map
            #(let [{id :id} %]
              (dom/td #js {:key id} (id row)))
            columns))))))

State update

// This version if you care about pure render
// You can also do this using react/lib/update: http://facebook.github.io/react/docs/update.html
var assign = require('react/lib/Object.assign');

var newRows = appState.rows.slice();
newRows.push({
  id: 4,
  name: "hello",
  episode: 4,
  lastViewed: "22-Jan-14"
});

var newAppState = assign({}, appState, {
  rows: newRows
});

// otherwise, appState.rows.push({...}); renderApp(appState);

// explicitly call renderApp since there's no binding between app-state and our App
renderApp(appState);
// you can use 'flux' or Backbone Models or whatever instead from your root if you want to
;; updating the atom will update our application, yay
(swap!
  app-state assoc :rows
  (conj (:rows @app-state)
        {:id 4 :name "hello" :episode 4 :last-viewed "22-Jan-14"}))

See the original CLJS source here: https://github.com/kimagure/tracker-om/blob/master/src/tracker_om/core.cljs

2
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
1