Can Reactjs be used as a View within Emberjs?

We have been using emberjs within our organization for about an year now (financial web application).

Recently there has been some discussions around whether the component approach of Reactjs is better suited for re-usability and would promote the component way of thinking.

Discussions mostly emanated after some engineers reviewed this video on Reactjs by Pete Hunt: Pete Hunt: React: Rethinking best practices -- JSConf EU - YouTube (Templates vs Components argument)

Questions:

  • Can Reactjs be used a view within Emberjs?
  • Does the React’s way of flush’n’re-write DOM (virtual) conflict with Ember’s own runloop?

Thank you for the tips and guidance,

Cheers,

1 Like

It would be very interesting to experiment with this. Hopefully, someone can contribute actual experience with this.

Have you checked out Ember’s Component Class?

That said, I’m not sure you’d need Ember components to recreate React’s features & API. From everything I’ve seen, React.js looks like an Ember.js View. For example, it seems React.renderComponent(Timer({}), mountNode); could be rewritten as App.TimerView.create.append().

Ember.Components are similar to React.js Componetns but their difference is what Pete highlights as a strength of React.js. Namely, combining merging HTML and JavaScript markup makes it easier for designers to contribute to projects and to test components because their state includes the controller and the template. It would be interesting to explore React.js components as a kind of Ember Component.

1 Like

@tarasm I’m a little confused by, “state includes the controller and the template.” As far as I can tell (and please correct me here), React.js doesn’t make a difference between the view and the controller. Their controller == an Ember.view. Also, the Ember View can hold all sorts of state in it. E.g. I could do this:

click: function(){
    this.set('checked', true)
}

Lastly, you mentioned React.js combines HTML & JS. While the use of Handlebars is certainly not to everyone’s taste, you can get the same effect by doing:

App.MyComponent = Ember.View.extend({
   template: Ember.Handlebars.compile(
     // HTML with handlebars goes here
   )
})

To me, the differences between React.js & Ember seem rather superficial – they user slightly different syntax to achieve the same thing. The API and concept seems similar. I think Ember’s suffered from an overemphasis on it’s use as a framework. When used as a library, I think it’s offers the same simplicity and API as frameworks like React.js.

1 Like

@scottmessinger I made a mistake, I should have said “component state includes the template and the state of the view”. Using template property is not the same thing as what React.js provides. If you look at “A Simple Example” that React provides

/** @jsx React.DOM */

var LikeButton = React.createClass({
  getInitialState: function() {
    return {liked: false};
  },
  handleClick: function(event) {
    this.setState({liked: !this.state.liked});
  },
  render: function() {
    var text = this.state.liked ? 'like' : 'unlike';
    return (
      <p onClick={this.handleClick}>
        You {text} this. Click to toggle.
      </p>
    );
  }
});

React.renderComponent(
  <LikeButton />,
  document.getElementById('example')
);

You can actually see a combination of template and javascript mixed together. I don’t think this would be a good idea in other areas of the app, but for components this is pretty useful.

I’m mostly interested in this as a mental exercise. I’m building a bunch of nested Ember components at work and it would be nice to keep component code together instead of jumping from templates to the component all of the time. But introducing React into my mix ( if possible ) would be an overkill.

Hi @tarasm, Sorry if I’m being dense about this, but I’m not yet seeing the difference. It seems Ember Views also have “template & javascript mixed together”. Here’s how I would write your example in Ember:

var LikeButton = Ember.View.extend({
  init: function() {
   this._super()
    this.set('liked', false};
  },
  likedText: function(){
    return(this.get('liked') ? 'like' : 'unlike')
  }.property('liked'),

  click: function(event) {
    this.set('liked', !this.get('liked')); // or this.toggleProperty('liked')
  },
  template: Ember.Handlebars.compile("
    <p>
        You {{likedText}} this. Click to toggle.
    </p>
  ")
});

LikeButton.create().appendTo('#example')

Help me understand – how is this different than React.js? We’ve changed some names (e.g. render => template, handleClick => click) but, as far as I can tell, the code samples are nearly identical.

7 Likes

@scottmessinger sorry it took so long to get back to you about this. I wanted to give it some thought. It looks like you’re right, they’re effectively the same. There’s a difference in how they handle rendering and changes to the screen (via virtual DOM) but otherwise the components look very similar to React widgets.

Thank you for taking your time get to the bottom of this.

I would like to extend this discussion with this blog post: http://swannodette.github.io/2013/12/17/the-future-of-javascript-mvcs/

I know the arguments in the first part of the piece are partially answered by Ember’s run loop. What do you think of the following ideas:

Because we always have the entire state of the UI in a single piece of data we can trivially serialize all of the important app state - we don’t need to bother with serialization protocols, or making sure that everyone implements them correctly. Om UI states are always serializable, always snapshotable.

This also means that Om UIs get undo for free. You can simply snapshot any state in memory and reinstate it whenever you like. It’s memory efficient as ClojureScript data structures work by sharing structure.

He then talks about playing back UI state like a VCR. I know there is more state than UI to worry, such as route state, etc, but this sounds very intriguing. Ember community thoughts on this?

3 Likes

I’m using React as the equivalent of an Ember View in some of the performance-sensitive parts of our application. It was fairly easy to implement, the process was pretty much like using a jQuery plugin, you just need to hook up mounting and unmounting the React component in didInsertElement and willClearRender.

The main gotcha is that you need to make sure you call forceUpdate on the React component whenever your data is updated.

This is what the code looks like:

App.LibraryView = Ember.View.extend({
  didInsertElement: function() {
    this.set('reactComponent', ReactComponent({
      content: this.get('content'),
      view: this
    }));
    React.renderComponent(this.get('reactComponent'), this.get('element'));
  },

  willClearRender: function() {
    React.unmountComponentAtNode(this.get('element'));
  }
});

Within the React component you can then use this.props.content.get('...') and this.props.content.set('...') to get and set properties and this.props.view to access the Ember view instance. Note that within the React event handlers if you set a property using this.props.content.set you will need to explicitly tell React to re-render by calling this.forceUpdate().

The list on this page is implemented using React components: http://hummingbird.me/users/vikhyat/library

The source code is here: https://github.com/hummingbird-me/hummingbird/blob/3dcde76e906f86c438f4ca11fd54481e7bf8c53e/app/assets/javascripts/react/library.js.jsx

4 Likes

Look interesting! The initial load takes a while but after the list is loaded, switch among list views is super fast. Do you have any data showing the performance gain of this approach versus a traditional group helper?

I didn’t do any actual scientific measurements but the best performance I was able to get out of Ember using the group helper and everything static unbound was about 10-15 seconds to render ~600 entries. Render time with this approach was actually acceptable until I had to add an itemViewClass to handle the dropdown and a jQuery plugin I was using. The performance drop was probably because of having to create a virtual view for every row once I specified an itemViewClass.

My initial React test in which I just modified the itemViewClass to render the row using Discourse brought the render time down 5-8 seconds. After that I tried using React to render the full list and that brought the render time down to 2-4 seconds.

At the moment React is a lot faster but I don’t believe that will be the case once HTMLbars is a thing, because React re-renders everything to a virtual DOM when anything is changed, does a diff with the current state and reconciles things whereas Ember actually keeps track of what changed and would update only what needs to change.

React’s reconcilation is still interesting though, it makes server-side rendering very easy since you can render things on the server and when React is initialized it will only attach event handlers.

4 Likes

Thanks @radq, this is really helpful comparison!

HTMLBars is going to significantly change the performance characteristics of Ember, so I don’t think there will be much of a benefit to using something like React to improve rendering performance.

2 Likes

Note that the second render of React for big lists is currently unnecessarily slow because of an issue that makes it run in O(n^2) instead of O(n). This has been fixed by the following diff and will be available in the next version.

https://github.com/facebook/react/pull/895

1 Like

How is the progress with HTMLBars now? Can’t wait to test it! :smile:

Thanks for heads up!

@krisselden and I are cranking away at it in our free time. I’ll be giving a talk at the SF Ember.js meetup on 1/21 about it. We’d love to have something to show for EmberConf :slight_smile:

4 Likes

Cool! The meetup is already full … Do post the slides! :smile:

Is there a writeup somewhere that goes over HTMLBars?