1 of 48

Fluxible

Isomorphic Flux Applications

Reza Akhavan

@jedireza

2 of 48

Agenda

...loading...

3 of 48

Agenda

  • Isomorphic™ JavaScript
  • Rendering React components
  • A mini Isomorphic™ React app
  • Bringing Flux to the server

4 of 48

Assumed

React / Flux / Express

5 of 48

Isomorphic™

i·so·mor·phic [adjective]

corresponding or similar in form and relations.

6 of 48

7 of 48

The Good Parts

8 of 48

SPA + SEO

9 of 48

Speed

10 of 48

<noscript>

11 of 48

Links

12 of 48

Rendering

with React

13 of 48

var React = require('react');

�module.exports = React.createClass({� handleClick: function () {� alert('Hello ' + this.props.name);� },� render: function () {� return (� <div onClick={this.handleClick}><div className="greeting">� Good morning {this.props.name}.� </div></div>� );� }�});

14 of 48

React.renderToStaticMarkup(...)

React.renderToString(...)

15 of 48

React.renderToStaticMarkup(Component({ name: 'JS Breakfast' }));

<div><div class="greeting">� Good morning JS Breakfast.� </div></div>

16 of 48

React.renderToString(Component({ name: 'JS Breakfast' }));

<div data-reactid=".292o9vx6ry8" data-react-checksum="-530623552">� <div class="greeting" data-reactid=".292o9vx6ry8.0">� <span data-reactid=".292o9vx6ry8.0.0">Good morning </span>� <span data-reactid=".292o9vx6ry8.0.1">JS Breakfast</span>� <span data-reactid=".292o9vx6ry8.0.2">.</span>� </div>�</div>

17 of 48

Let’s Fiddle

with This

18 of 48

A Mini

Isomorphic React App

https://github.com/jedireza/mini-isomorphic-react

19 of 48

Flux

Dispatcher

Store

View

one instance

singletons

Action

fire & forget

instances

20 of 48

Fluxible

Dispatcher

Store

View

one instance

per request

one instance per request

Action

instances

fire & forget + async

21 of 48

Isolated

Dispatcher

Store

View

one instance

per request

one instance per request

Action

instances

fire & forget + async

Per Request

22 of 48

Actions

You can create any application state through some set of action calls.

23 of 48

// ./actions/navigate.js

function navigate (context, params, done) {

var route = context.router.getRoute(params.path);

context.dispatch('CHANGE_ROUTE_START', route);�� context.executeAction(route.action, function (err, data) {

// route action now complete

context.dispatch('CHANGE_ROUTE_SUCCESS', route);

done();

});�}

module.exports = navigate;

24 of 48

Context

Action / Store / Component

25 of 48

Routing

fluxible-router / react-router

26 of 48

State

Dehydrate / Rehydrate

27 of 48

// ./stores/Article.js

module.exports = createStore({� // ...dehydrate: function () {� return {� articles: this.articles,� current: this.current� };� },� rehydrate: function (state) {� this.articles = state.articles;� this.current = state.current;� }�});

28 of 48

Plugins

http://fluxible.io/api/plugins.html

29 of 48

// ./app.js

var React = require('react');�var Fluxible = require('fluxible');�var FetchrPlugin = require('fluxible-plugin-fetchr');��var app = new Fluxible({/* config */});

// apply the plugin�app.plug(FetchrPlugin({/* config */)});��module.exports = app;

30 of 48

// ./actions/getArticle.js

function getArticle (context, params, done) {

context.service.read('articles', {id: params.id}, function (err, article) {

// ...� });�}

module.exports = getArticle;

31 of 48

Isomorphic

Data Fetching

32 of 48

// ./services/Article.jsvar db = require(/* some data resource */);

�module.exports = {� name: 'articles',� read: function (req, resource, params, config, callback) {� var query = { id: params.id };� db.articles.findOne(query, function (err, article) {� if (err) {� return callback(err);� }� callback(null, article);� });� }�};

33 of 48

// ./server.js

var Express = require('express');�var App = require('./app');�var ArticleService = require('./services/Article');�

var server = Express();�var fetchrPlugin = App.getPlugin('FetchrPlugin');

FetchrPlugin.registerService(ArticleService);�server.use(fetchrPlugin.getXhrPath(), fetchrPlugin.getMiddleware());

// ...�server.listen(3000);

34 of 48

// ./actions/getArticle.js

function getArticle (context, params, done) {

context.dispatch('GET_ARTICLE_START', params);

context.service.read('articles', {id: params.id}, function (err, article) {

if (err) {� return context.dispatch('GET_ARTICLE_FAIL', params);� }� context.dispatch('GET_ARTICLE_SUCCESS', article);

done();

});�}

module.exports = getArticle;

35 of 48

The Fluxible

Lifecycle

36 of 48

Action

37 of 48

Dispatcher

Action

38 of 48

Dispatcher

Store

Action

39 of 48

Dispatcher

Store

View

Action

40 of 48

Dispatcher

Store

View

Action

Per Request

41 of 48

Dispatcher

Store

View

Action

Dehydrate Server

state

html

42 of 48

Rehydrate Browser

Dispatcher

Store

View

Action

Dehydrate Server

state

html

43 of 48

Dispatcher

Store

View

Action

Rehydrate Browser

Dispatcher

Store

View

Action

Dehydrate Server

state

html

44 of 48

Demos

github.com/yahoo/flux-examples

45 of 48

Open Source,

Open Minded

46 of 48

fluxible.io

For docs, guides and links.

(built with Fluxible)

47 of 48

Core Team

Michael Ridgway

Lingyan Zhu

Seth Bertalotto

Rajiv Tirumalareddy

Kaeson Ho

48 of 48

Thank You

Reza Akhavan

@jedireza