Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Introdução ao React

Sponsored · SiteGround - Reliable hosting with speed, security, and support you can count on.

Introdução ao React

Avatar for Gabriel Sobrinho

Gabriel Sobrinho

August 08, 2015
Tweet

More Decks by Gabriel Sobrinho

Other Decks in Programming

Transcript

  1. React • Biblioteca para construir interfaces de usuário • Implementa

    apenas a camada de view • Trabalha com Virtual DOM para ser performático • Fluxo de dados em direção única • Desenvolvido e mantido pelo Facebook/Instagram
  2. Virtual DOM • Representação em memória dos nodes usando objetos

    puros • Em tese pode ser implementado adapter para qualquer client (browser, mobile, ascii, etc) • Permite computar o diff de diferentes momentos ou nodes • Com o diff computado é possível realizar um patch no renderizado com o menor impacto possível
  3. Virtual DOM function VNode (name, attributes, content) { this.name =

    name; this.attributes = attributes; this.content = content; } vn1 = new VNode( "p", { className: "failure", id: "failure" }, "Hello" ); vn2 = new VNode( "p", { className: "success", role: "message" }, "World" );
  4. Virtual DOM function render (vn) { var attr, n =

    document.createElement(vn.name); for (attr in vn.attributes) { n[attr] = vn.attributes[attr]; } n.innerHTML = vn.content; return n; } n1 = render(vn1); document.getElementById("app").appendChild(n1);
  5. Virtual DOM function diff (vn1, vn2) { var attr, diff

    = []; for (attr in vn1.attributes) { if (!(attr in vn2.attributes)) { diff.push([attr, undefined]); } } for (attr in vn2.attributes) { if (vn1.attributes[attr] !== vn2.attributes[attr]) { diff.push([attr, vn2.attributes[attr]]); } } if (vn1.content != vn2.content) { diff.push(["innerHTML", vn2.content]); } return diff; }
  6. Virtual DOM vn1 = new VNode( "p", { className: "failure",

    id: "failure" }, "Hello" ); vn2 = new VNode( "p", { className: "success", role: "message" }, "World" ); diff = diff(vn1, vn2); [ ["id", undefined], ["className", "success"], ["role", "message"], ["innerHTML", "World"] ]
  7. Virtual DOM function patch (n, diff) { var idx, pair;

    for (idx in diff) { pair = diff[idx]; if (pair[1]) { n[pair[0]] = pair[1]; } else { delete n[pair[0]]; } } } patch(n1, diff);
  8. Virtual DOM • Representação virtual do DOM • Renderizada a

    representação • Computada a diferença • Aplicado o menor patch possível
  9. JSX • Transpiler de XML para JavaScript • Uso opcional

    mas recomendado • Elimina a necessidade de conhecer a API da biblioteca vDOM utilizada pelo React • Facilita manutenção dos componentes por desenvolvedores casuais (designers e etc)
  10. JSX Hite = React.createClass({ displayName: "Hite", render: function () {

    return React.createElement( "a", { href: "http://www.hite.com.br/" }, "Hite" ); } });
  11. JSX Hite = React.createClass({ render: function () { return (

    <a href="http://www.hite.com.br"> www.hite.com.br </a> ); } });
  12. JSX • Infere automaticamente o displayName • Trabalha com componentes

    em namespace • Spread operator (similar ao splat operator do ruby)
  13. Componentes • React se resume basicamente apenas a construir componentes

    • Não possui nenhuma opinião sobre como a arquitetura da sua aplicação deve ser feita (é uma biblioteca e não um framework) • Componentes são bem definidos, previsíveis, encapsulados, testáveis e re-usáveis
  14. Componentes var Avatar = React.createClass({ render: function() { return (

    <div> <ProfilePic username={this.props.username} /> <ProfileLink username={this.props.username} /> </div> ); } });
  15. Componentes var ProfilePic = React.createClass({ render: function() { var src

    = 'https://graph.facebook.com/' + this.props.username + '/picture'; return ( <img src={src} /> ); } });
  16. Componentes var ProfileLink = React.createClass({ render: function() { var href

    = 'https://www.facebook.com/' + this.props.username; return ( <a href={href}> {this.props.username} </a> ); } });
  17. Props • Armazena argumentos externos do componente • Somente leitura

    • Pode ser qualquer valor, desde primitivos a objetos complexos • IMO deve conter apenas primitivos para facilitar o cálculo de rendering • Permite validar o valor recebido, inclusive obrigatoriedade (serve para documentar e pseudo tipagem estática)
  18. Props var Gravatar = React.createClass({ render: function() { var name

    = this.props.name, src = 'https://gravatar.com/ avatar/' + md5(this.props.email); return ( <img alt={name} src={src} /> ); } });
  19. Props var Gravatar = React.createClass({ propTypes: { name: React.PropTypes.string, email:

    React.PropTypes.string.isRequired, }, render: function() { var name = this.props.name, src = 'https://gravatar.com/avatar/' + md5(this.props.email); return ( <img alt={name} src={src} /> ); } });
  20. State • Armazena o estado interno do componente • Permite

    leitura e escrita • O componente é automaticamente atualizado no DOM quando uma alteração é escrita • Deve ser evitado sempre que possível (ainda falaremos sobre o Flux para evitar isso) • Não permite validação de tipos já que se trata de dados internos do próprio componente • IMO deveria permitir já que podemos confundir o tipo do dado e causar um comportamento inesperado
  21. State var Counter = React.createClass({ getInitialState: function() { return {

    count: 0 }; }, componentDidMount: function() { this.interval = setInterval(this.increment, 1000); }, componentWillUnmount: function() { clearInterval(this.interval); }, render: function() { var count = this.state.count; return <p>{count}</p>; }, increment: function() { this.setState({count: this.state.count + 1}); } });
  22. Hooks • componentWillMount
 Executado antes do componente ser renderizado no

    DOM • componentDidMount
 Executado após o componente ser renderizado no DOM • componentWillReceiveProps
 Executado antes do componente receber novas propriedades • componentWillUpdate
 Executado antes do componente ser atualizado (props e/ou state) • componentDidUpdate
 Executado após o componente ser atualizado (props e/ou state) • componentWillUnmount
 Executado antes do componente ser removido do DOM
  23. Hooks componentWillUpdate: function() { var node = this.getDOMNode(); this.shouldScrollBottom =

    node.scrollTop + node.offsetHeight === node.scrollHeight; } componentDidUpdate: function() { if (this.shouldScrollBottom) { var node = this.getDOMNode(); node.scrollTop = node.scrollHeight } }
  24. Mixins • Proposta nativa para implementar reuso de código entre

    diferentes componentes • Algumas vezes chamado de cross-cutting concern, interesses transversais ou características transversais • Ainda funciona mas foi deprecado com a entrada do uso do ES6 mas pode ser substituído pelo cocktail ou composition • Prefiro chamar apenas de mixin ¯\_(ツ)_/¯
  25. Mixins componentDidMount: function() { if (this.props.autoIncrement) { this.interval = setInterval(this.increment,

    1000); } } componentWillUnmount: function() { if (this.interval) { clearInterval(this.interval); } }
  26. Mixins componentDidMount: function() { this.incrementAInterval = setInterval(this.incrementA, 1000); this.incrementBInterval =

    setInterval(this.incrementB, 1000); } componentWillUnmount: function() { clearInterval(this.incrementAInterval); clearInterval(this.incrementBInterval); }
  27. Mixins SetIntervalMixin = { componentWillMount: function() { this.intervals = [];

    }, setInterval: function() { this.intervals.push(setInterval.apply(null, arguments)); }, componentWillUnmount: function() { this.intervals.map(clearInterval); } };
  28. Mixins var Counter = React.createClass({ getInitialState: function() { return {

    count: 0 }; }, componentDidMount: function() { this.interval = setInterval(this.increment, 1000); }, componentWillUnmount: function() { clearInterval(this.interval); }, render: function() { var count = this.state.count; return <p>{count}</p>; }, increment: function() { this.setState({count: this.state.count + 1}); } });
  29. Mixins var Counter = React.createClass({ mixins: [SetIntervalMixin], getInitialState: function() {

    return { count: 0 }; }, componentDidMount: function() { this.setInterval(this.increment, 1000); }, render: function() { var count = this.state.count; return <p>{count}</p>; }, increment: function() { this.setState({count: this.state.count + 1}); } });
  30. Mixins ScrollToBottomMixin = { componentWillUpdate: function() { var node =

    this.getDOMNode(); this.shouldScrollBottom = node.scrollTop + node.offsetHeight === node.scrollHeight; }, componentDidUpdate: function() { if (this.shouldScrollBottom) { var node = this.getDOMNode(); node.scrollTop = node.scrollHeight } } };
  31. Formulários • input, textarea, select recebem iteração do usuário que

    mutam o estado do input (input.value e input.checked) • Podemos escutar esses eventos para reagir conforme necessário • Por padrão o React mantém o input atualizado com o valor informado pelo componente • React já possui um mixin para 2-way binding
  32. Formulários var NoLink = React.createClass({ getInitialState: function() { return {message:

    'Hello!'}; }, handleChange: function(event) { this.setState({message: event.target.value}); }, render: function() { var message = this.state.message; return <input type="text" value={message} onChange={this.handleChange} />; } });
  33. Formulários var WithLink = React.createClass({ mixins: [React.addons.LinkedStateMixin], getInitialState: function() {

    return { message: 'Hello!' }; }, render: function() { return <input type="text" valueLink={this.linkState('message')} />; } });
  34. Flux • Arquitetura proposta pelo Facebook para criar aplicações client-side

    • É uma arquitetura e não uma implementação • Bastante similar a proposta original do MVC • Já existem várias implementações e quase todas diferem da proposta original • Ainda existem questões que não foram especificadas pelo Flux
  35. Flux • Facebook: https://github.com/facebook/flux • Yahoo: http://fluxible.io • Josh Perez:

    http://alt.js.org • Hite: https://github.com/samuelsimoes/fluxo
  36. Fluxo • Implementação da arquitetura Flux pela Hite • A

    diferença é que não temos o Dispatcher • Actions conversam diretamente com os Stores (ainda não sabemos se isso é bom ou ruim) • Inspirado nas boas idéias do Backbone Model, Backbone Collection, Ember e Flux • Já estamos utilizando em produção
  37. Fluxo Schedule = Fluxo.Store.extend({ computed: { date: ["change:at"] }, date:

    function () { return this.data.at.split("T")[0]; } });
  38. Fluxo Schedules = Fluxo.CollectionStore.extend({ store: Schedule, computed: { dates: ["add",

    "remove"] }, dates: function () { return this.map(function (store) { return store.get("date"); }); } });
  39. Fluxo schedules = Schedules.new([ { id: 1, at: "2015-07-04T04:00:00.000Z", professional_id:

    1, professional_name: "John" }, { id: 3, at: "2015-07-05T04:00:00.000Z", professional_id: 1, professional_name: "John" } ]);
  40. Fluxo schedules.toJSON() { data: { dates: ["2015-07-04", "2015-07-05"], }, stores:

    [ { id: 1, at: "2015-07-04T04:00:00.000Z", professional_id: 1, professional_name: "John", date: "2015-07-04" }, { id: 3, at: "2015-07-05T04:00:00.000Z", professional_id: 1, professional_name: "John", date: "2015-07-05" } ] }
  41. Fluxo var schedules = new Schedules(window.schedulesData); var MedicalReferralComponent = FluxoReactConnectStores(MedicalReferralComponent,

    { schedules: schedules }); React.render( React.createElement(MedicalReferralComponent), document.getElementById("app-container") );