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

Introdução ao React

Introdução ao React

C2dc9c02ce7a041285725a4fc9e5f6d2?s=128

Gabriel Sobrinho

August 08, 2015
Tweet

Transcript

  1. Introdução ao React Gabriel Sobrinho

  2. hite.com.br

  3. 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
  4. Conceitos

  5. None
  6. 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
  7. 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" );
  8. 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);
  9. 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; }
  10. 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"] ]
  11. 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);
  12. Virtual DOM delete n1.id; n1.className = "success"; n1.role = "message";

    n1.innerHTML = "World";
  13. Virtual DOM • Representação virtual do DOM • Renderizada a

    representação • Computada a diferença • Aplicado o menor patch possível
  14. None
  15. 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)
  16. JSX Hite = React.createClass({ displayName: "Hite", render: function () {

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

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

    em namespace • Spread operator (similar ao splat operator do ruby)
  19. None
  20. 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
  21. Componentes React.render( <Avatar username="pwh" />, document.getElementById('example') );

  22. Componentes var Avatar = React.createClass({ render: function() { return (

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

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

    = 'https://www.facebook.com/' + this.props.username; return ( <a href={href}> {this.props.username} </a> ); } });
  25. Componentes <div> <img src='https://graph.facebook.com/pwh/picture'> <a href='https://www.facebook.com/pwh'> pwh </a> </div>

  26. None
  27. 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)
  28. 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} /> ); } });
  29. 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} /> ); } });
  30. None
  31. 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
  32. 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}); } });
  33. None
  34. 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
  35. Hooks componentWillMount: function() { this.$ = jQuery; }

  36. Hooks componentDidMount: function() { this.interval = setInterval(this.increment, 1000); } componentWillUnmount:

    function() { clearInterval(this.interval); }
  37. Hooks componentWillReceiveProps: function(nextProps) { this.setState({ likesIncreasing: nextProps.likeCount > this.props.likeCount });

    }
  38. 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 } }
  39. None
  40. 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 ¯\_(ツ)_/¯
  41. Mixins componentDidMount: function() { this.interval = setInterval(this.increment, 1000); } componentWillUnmount:

    function() { clearInterval(this.interval); }
  42. Mixins componentDidMount: function() { if (this.props.autoIncrement) { this.interval = setInterval(this.increment,

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

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

    }, setInterval: function() { this.intervals.push(setInterval.apply(null, arguments)); }, componentWillUnmount: function() { this.intervals.map(clearInterval); } };
  45. 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}); } });
  46. 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}); } });
  47. 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 } } };
  48. None
  49. 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
  50. 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} />; } });
  51. 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')} />; } });
  52. None
  53. 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
  54. Flux

  55. Flux

  56. Flux • Facebook: https://github.com/facebook/flux • Yahoo: http://fluxible.io • Josh Perez:

    http://alt.js.org • Hite: https://github.com/samuelsimoes/fluxo
  57. None
  58. 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
  59. Fluxo

  60. Fluxo Schedule = Fluxo.Store.extend({ computed: { date: ["change:at"] }, date:

    function () { return this.data.at.split("T")[0]; } });
  61. Fluxo schedule = Schedule.new({ id: 1, at: "2015-07-04T04:00:00.000Z", professional_id: 1,

    professional_name: "John" });
  62. Fluxo schedule.toJSON() { id: 1, at: "2015-07-04T04:00:00.000Z", professional_id: 1, professional_name:

    "John", date: "2015-07-04" }
  63. Fluxo Schedules = Fluxo.CollectionStore.extend({ store: Schedule, computed: { dates: ["add",

    "remove"] }, dates: function () { return this.map(function (store) { return store.get("date"); }); } });
  64. 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" } ]);
  65. 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" } ] }
  66. Fluxo var schedules = new Schedules(window.schedulesData); var MedicalReferralComponent = FluxoReactConnectStores(MedicalReferralComponent,

    { schedules: schedules }); React.render( React.createElement(MedicalReferralComponent), document.getElementById("app-container") );
  67. Fluxo Publicado em https://github.com/samuelsimoes/fluxo

  68. None
  69. Dúvidas?

  70. Obrigado!

  71. Referências • https://facebook.github.io/react/index.html • https://github.com/Matt-Esch/virtual-dom • https://pt.wikipedia.org/wiki/Cross-cutting_concern • http://blog.vjeux.com/2013/javascript/scroll-position- with-react.html

    • http://blog.andrewray.me/flux-for-stupid-people/ • https://facebook.github.io/flux/