React at

Scandinavia Online

About me

  • Scandinavia Online
  • Consulting / Training
  • JavaScript <3
  • eiriklv @ github
  • eiriklv @ twitter
  • http://vullum.io

Eirik Vullum

Scandinavia Online

  • News aggregation and curation
  • Search (Kvasir)
  • 1.5M unique users / week (sol.no)

Why React?

Isomorphism

  • Experimental
  • react-async
  • node

react-async

Black magic..? (yes)

getInitialStateAsync: function(callback) {
  api.articles.get({
    limit: 10,
    offset: 0
  }, function(err, result) {
    callback(err, { articles: result });
  });
},

//...

ReactAsync.renderToStringAsync(...);

Routing + History State

react-router?

linkClickHandler: function(event) {
  if (isBrowser && hasHistory) {
    history.pushState({
      articles: this.state.articles,
      scrollPosition: document.body.scrollTop
    }, null, '/?offset=' + this.state.articles.length);
  }

  // no event.preventDefault();
},
componentDidMount: function() {
  if (isBrowser && hasHistory && history.state) {
    this.setState({
      articles: history.state.articles,
    });

    imagesLoaded(this.getDOMNode(), function() {
      window.scrollTo(0, history.state.scrollPosition);
      history.replaceState(null, null, window.location.origin);
    });
  }
},

From jQuery to React

// old jquery code from the news-stream
// ??
<NewsStreamContainer styles={styles}>
  <CategoryNavigation
    categories={this.state.categories}
    activeCategory={this.state.activeCategory}
    onCategoryClick={this.onCategoryClick}
  />
  <CategoryContent>
    <SourceNavigation
      sources={currentCategory.sources}
      activeSource={this.state.activeSource}
      onSourceClick={this.onSourceClick}
    />
    <SourceContent>
      <ArticleList
        articles={articles}
      />
    </SourceContent>
  </CategoryContent>
</NewsStreamContainer>

Standalone components

var React = require('react');
var NewsStream = require('sol-react-news-stream');

React.renderComponent(
  React.createElement(NewsStream, { apiURL: apiURL }),
  document.getElementById('newsStream')
);

On Desktop

Client-side js only

var React = require('react');
var NewsStream = require('sol-react-news-stream');

var App = React.createClass({
  render: function() {
    return (
      <div>
        <NewsStream apiURL={apiURL} />
      </div>
    );
  }
});

On Mobile

Server + client-side

Stylesheets

brfs

+

inline style tag

// fetch styles
var styles = fs.readFileSync(
  __dirname + '/style.min.css',
  'utf8'
);

// pass it to component
<NewsStream styles={styles}>..</NewsStream>

// inject the styles as a tag
<style 
  dangerouslySetInnerHTML={{__html: this.props.styles }}
/>

webpack

+ loader/transforms

+ pre-publish build

(Probably a better solution)

Pain points

  • A lot is still in flux (no pun intended)
  • react-async (fibers)
  • Self-serving components
    + dependencies management
  • Ads and iframes (yuck..)

Takeaways for us

  • Great performance
  • Cleaner applications
  • Development is more fun!
  • Isomorphism is awesome
  • Self-serving components will be awesome
    (when we get it right..)
  • Works well on its own and as a complement

Plugs

NodeConf ONE-SHOT Oslo (May 23.)

NDC Oslo (June 19.)

Building a News Aggregator using Streams and Functional JavaScript

Building Isomorphic Applications
(JavaScript Optional)