25/09/2015 Development / java script

Essa semana eu comecei a dar uma olhada bem superficial no react e a principio comecei bem de leve, abri uma paginazinha no google, digitei react jsfiddle, entrei no primeiro exemplo e fui brincando.

A primeira impressão fiquei com pé atras, por ter visto o html misturado ao javascript, mas quando caiu a ficha que aquilo ali se tratava de um componente e que um componente tem vida propria e pode se comunicar com qualquer outro componente, pensei como existem pessoas inteligentes na face da terra!!!

E a partir dai fui brincando, brincando e fazendo os testes.

A minha missão era fazer uma pagina renderizar N componentes e dentro desses componentes, poderiam ter N componentes e ai por diante...

O desafio maior é que essa estrutura estava em um JSON.

var spacey = [{
    type : 'Position',
    position: 'x01',
    sm: 12,
    md: 6,
    lg: 6,
    items : [{
        type : 'Carrousel',
        items : [{
            type : 'Imagem',
            imgP : 'http://www.hiperativos.com.br/wp-content/uploads/2013/11/background.jpg'
        },{
            type : 'Imagem',
            imgP : 'http://www.hiperativos.com.br/wp-content/uploads/2013/11/background.jpg'
        },{
            type : 'Imagem',
            imgP : 'http://www.hiperativos.com.br/wp-content/uploads/2013/11/background.jpg'
        },{
            type : 'Imagem',
            imgP : 'http://www.hiperativos.com.br/wp-content/uploads/2013/11/background.jpg'
        }]
    }]
},{
    type : 'Position',
    position: 'x02',
    sm: 12,
    md: 6,
    lg: 6,
    items : [{
        type : 'Carrousel',
        items : [{
            type : 'Imagem',
            imgP : 'http://www.hiperativos.com.br/wp-content/uploads/2013/11/background.jpg'
        },{
            type : 'Imagem',
            imgP : 'http://www.hiperativos.com.br/wp-content/uploads/2013/11/background.jpg'
        },{
            type : 'Imagem',
            imgP : 'http://www.hiperativos.com.br/wp-content/uploads/2013/11/background.jpg'
        },{
            type : 'Imagem',
            imgP : 'http://www.hiperativos.com.br/wp-content/uploads/2013/11/background.jpg'
        }]
    }]
},{
    type : 'Position',
    position: 'x03',
    sm: 12,
    md: 6,
    lg: 6,
    items : [{
        type : 'Carrousel',
        items : [{
            type : 'Imagem',
            imgP : 'http://www.hiperativos.com.br/wp-content/uploads/2013/11/background.jpg'
        },{
            type : 'Imagem',
            imgP : 'http://www.hiperativos.com.br/wp-content/uploads/2013/11/background.jpg'
        },{
            type : 'Imagem',
            imgP : 'http://www.hiperativos.com.br/wp-content/uploads/2013/11/background.jpg'
        },{
            type : 'Imagem',
            imgP : 'http://www.hiperativos.com.br/wp-content/uploads/2013/11/background.jpg'
        }]
    }]
},{
    type : 'Position',
    position: 'x04',
    sm: 12,
    md: 6,
    lg: 6,
    items : [{
        type : 'Carrousel',
        items : [{
            type : 'Imagem',
            imgP : 'http://www.hiperativos.com.br/wp-content/uploads/2013/11/background.jpg'
        },{
            type : 'Imagem',
            imgP : 'http://www.hiperativos.com.br/wp-content/uploads/2013/11/background.jpg'
        },{
            type : 'Imagem',
            imgP : 'http://www.hiperativos.com.br/wp-content/uploads/2013/11/background.jpg'
        },{
            type : 'Imagem',
            imgP : 'http://www.hiperativos.com.br/wp-content/uploads/2013/11/background.jpg'
        }]
    }]
}];

module.exports.spacey = spacey;

Ou seja, dentro desse JSON eu tenho um componente chamado Position, que dentro dele tem um componente chamado Carrousel que dentro dele tem componentes chamado Imagem.

E o desafio ficou maior quando eu decide aproveitar ao máximo o poder do REACT e fazer uma aplicação Isomorphica que respondia tanto no client como no server com o mesmo código :-)

Primeiro criei um servidor usando o EXPRESS

Server.js

// server.js

var express = require('express'),
path = require('path'),
app = express(),
port = 4444,
bodyParser = require('body-parser');

// JSX transpiler
require("node-jsx").install();

app.use(express.static(path.join(__dirname, 'public')));
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'ejs');

require('./app/routes/core-routes.js')(app);

app.get('*', function(req, res) {
    res.json({
        "route": "Ops, não encontrado"
    });
});

app.listen(port);
console.log('Server is Up and Running at Port : ' + port);

Feito isso minha preocupação foi fazer os componentes

Componente Position

/** @jsx React.DOM */

var React = require('react');
var Position = require('./Position');
var Carrousel = require('./Carrousel');
var Imagem = require('./Imagem');

var id = 0;
function newId(){
    return id++;
}
var Position = React.createClass({

    componentDidMount: function() {
        setTimeout(function(){
            //sp.getPublication();
        }, 5000); 
    },


    render: function() {

        var obj = {};
        obj['col-sm-' + this.props.properties.sm] = this.props.properties.sm;
        obj['col-md-' + this.props.properties.md] = this.props.properties.md;
        obj['col-lg-' + this.props.properties.lg] = this.props.properties.lg;
        obj['spacey-oas'] = 'spacey-oas';

        var classes = React.addons.classSet(obj);
        var dataPos = this.props.properties.position;


        if(this.props.items){
            var components = this.props.items.map(function(component){
            var module = React.createFactory(require('./' + component.type));
            var instance = React.createElement(module, {items: component.items, properties: component, key: newId()});
                return (instance);
            });            
        }
 
        return (<div className={ classes } data-pos={dataPos}><div className="well">{components}</div></div>);
    }
});

module.exports = Position;

Componente Carrousel

/** @jsx React.DOM */

var React = require('react/addons');
var Imagem = require('./Imagem');

var id = 0;
function newId(){
    return id++;
}

var Carrousel = React.createClass({

    //antes de carregar
    componentDidMount: function() {
        jQuery(this.getDOMNode()).not('.ready').addClass('ready').slick({infinite: true,slidesToShow: 1,slidesToScroll: 1});
    },

    //depois de carregar
    componentWillMount: function() {
    },

    render: function() {
        var components = this.props.items.map(function(component){
        var module = React.createFactory(require('./' + component.type));
        var instance = React.createElement(module, {items: component.items, properties: component, key: newId()});
            return (<div>{instance}</div>);            
        });

        return (<div className="slick-slider">{components}</div>);
    }
});

module.exports = Carrousel;

Componente Imagem

/** @jsx React.DOM */

var React = require('react/addons');

var Imagem = React.createClass({
    render: function() {
        return (<img src={this.props.properties.imgP} className='imagem img-responsive'/>);
    }
});

module.exports = Imagem;

Componente MyComponents - Responsavel por chamar todos os componentes.

/** @jsx React.DOM */

var React = require('react');
var Position = require('./Position');
var id = 0;
function newId(){
    return id++;
}

var MyComponents = React.createClass({
    render: function() {
        var obj = [].concat(this.props.obj);
        var components = obj.map(function(component){
        var module = React.createFactory(require('./' + component.type));
             return (React.createElement(module, {items: component.items, properties: component, key : newId() } ));            
        });
 
        return (<div>{components}</div>);
    }
});

module.exports = MyComponents;

3) Feito isso, fui fazer o arquivo que iria renderizar todo esse processo, o arquivo MAIN.JS do Client e o meu Core-Routes.js no Server

Core-routes.js

/* Server Side */
var React = require('react');
var MyComponents = React.createFactory(require('../components/MyComponents'));
var spacey = require('../data/spacey.js').spacey;
var http = require('http');

module.exports = function(app) {

    app.get('/', function(req, res){
        var reactHtml = React.renderToString(MyComponents({'obj' : spacey}));
        res.render('index.ejs', {reactOutput: reactHtml});
    });
};

Main.js - Client

/** @jsx React.DOM */
/* Client Side */    

var React = require('react');
var spacey = require('./data/spacey.js').spacey;

var MyComponents = require('./components/MyComponents');
var container = document.getElementById("react-main-mount");

var app = React.createElement(MyComponents, {'obj' : spacey});
app = React.render(app, container);

E por ultima a minha view que iria fazer o merge com os dados

  <div class="container-fluid">
    <div class="row">
      <div id="react-main-mount">
        <%- reactOutput %>
      </div>
    </div>
  </div>

<!-- se comentar esse cara só renderiza via server  -->
<script src="/main.js"></script>

E tambem um arquivo importantissimo que transforma os componentes no main.js, para isso usei o gulp

var gulp       = require('gulp'),
browserify = require('gulp-browserify'),
watch = require('gulp-watch'),
livereload = require('gulp-livereload');

gulp.task('scripts', function () {

    gulp.src(['app/main.js'])
        .pipe(browserify({
            debug: true,
            transform: [ 'reactify' ]
        }))
        .pipe(livereload())
        .pipe(gulp.dest('./public/'));

});

gulp.task('watch', function() {
    livereload.listen();
    gulp.watch('app/**/*.js', ['scripts']);
});

gulp.task('default', ['scripts','watch']);

Ai foi juntar tudo isso e plaaaay! A parada é absurdamente animal

Espero que sirva para alguém ;-)