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

Bring Your Web Application Architecture to the Next Level With React.JS

Bring Your Web Application Architecture to the Next Level With React.JS

React.JS is a very powerful library for building user interfaces and the new, cool kid in the JavaScript world. But it is also very interesting for creating a fast, maintainable and interactive web application. In this talk I'll show what React is all about and how you can combine and integrate it’s power with your web application, even if you have to render out HTML on the server side. Especially common pitfalls for getting data from your backend to React will be covered. The result will be a flexible, component based architecture that enables developers to take page elements, like a single "follow" button, and place it everywhere on the site without having to duplicate any backend code, JS, HTML, CSS or AJAX endpoints in the process.

8e82eb7e128a14a16d642ae55227339b?s=128

Bastian Hofmann

April 10, 2016
Tweet

Transcript

  1. Bring your web application to the next level with React.JS

    @BastianHofmann
  2. ?

  3. Application architecture

  4. Code and component  re-use

  5. Rapid Development

  6. Handling large code-bases

  7. With React.js

  8. With small and independent components

  9. webserver HTML browser JS controller

  10. webserver HTML browser JS Ajax controller

  11. webserver HTML browser JS Ajax controller

  12. de duplication ode duplication code duplication code duplication code duplication

    code duplication code duplication code duplication code duplication code duplication code duplication code duplication code duplication code duplicatio code duplicat code duplic code dup code du code cod co co
  13. A few words about me

  14. None
  15. None
  16. http://speakerdeck.com/u/bastianhofmann

  17. Application architecture

  18. None
  19. status quo

  20. webserver loadbalancer pgsql memcached mongodb services

  21. webserver

  22. webserver HTML browser JS Ajax controller

  23. None
  24. MVC

  25. Duplication and only some Code re- use

  26. We can do  better

  27. Small components over big controllers

  28. None
  29. None
  30. None
  31. None
  32. None
  33. None
  34. None
  35. Self contained

  36. Can be used everywhere

  37. JS is part of the component

  38. CSS can be part of the component

  39. http://facebook.github.io/react/

  40. JavaScript UI Library

  41. Many small, self contained, reusable components

  42. var HelloMessage = React.createClass(
 {
 render: function () {
 return

    <div>Hello {this.props.name}</div>;
 }
 }
 );
 
 ReactDOM.render(<HelloMessage name="John" />, mountNode);
  43. var Timer = React.createClass({
 getInitialState: function () {
 return {secs:

    0};
 },
 tick: function () {
 this.setState({secs: this.state.secs + 1});
 },
 componentDidMount: function () {
 this.interval = setInterval(this.tick, 1000);
 },
 componentWillUnmount: function () {
 clearInterval(this.interval);
 },
 render: function () {
 return (<div> Seconds Elapsed: {this.state.secs}</div> );
 }
 });
 
 ReactDOM.render(<Timer />, mountNode);
  44. var TodoList = React.createClass(
 {
 render: function () {
 var

    createItem = function (itemText) {
 return <li>{itemText}</li>;
 };
 return ( <ul> {this.props.items.map(createItem)} </ul> );
 }
 }
 );
  45. var TodoApp = React.createClass({
 render: function () {
 return (


    <div>
 <h3>TODO</h3>
 <TodoList items={this.props.items} />
 </div>
 );
 }
 });
  46. Getting the data in there

  47. PHP Backend JSON React Frontend

  48. PHP Backend JSON React Frontend

  49. PHP Backend JSON React Frontend

  50. PHP Backend JSON React Frontend

  51. var TodoApp = React.createClass({
 getInitialState: function () {
 return {items:

    […]};
 },
 render: function () {
 return (
 <div>
 <h3>TODO</h3>
 <TodoList items={this.state.items} />
 </div>
 );
 }
 });
  52. Problematic

  53. Remember

  54. Self-contained

  55. Reusable

  56. PHP Backend JSON React Frontend

  57. PHP Backend JSON React Frontend

  58. PHP Backend JSON React Frontend

  59. Overfetching

  60. Underfetching

  61. Solutions

  62. Flux Datastores

  63. PHP Backend React Frontend Datastores

  64. Requirements

  65. PHP Backend React Frontend

  66. Profile Publications Publication Publication Publication AboutMe LeftColumn Image Institution Menu

    React Frontend
  67. Profile Publications Publication Publication Publication AboutMe LeftColumn Image Menu PHP

    Backend Request Response Institution
  68. LeftColumn Image Menu React Frontend

  69. LeftColumn Image Menu Request Response PHP Backend

  70. Remember:  self contained

  71. Profile Publications Publication Publication Publication AboutMe LeftColumn Image Menu Account

    Account Account Account Account Publication1 Publication2 Publication3 Institution
  72. Do not fetch data directly

  73. Sssssssllllooooowww

  74. Require stuff

  75. http://www.infoq.com/presentations/Evolution-of-Code- Design-at-Facebook/

  76. None
  77. Widget Widget Widget Widget Preparer Resolver Resolver Services Connector Interfaces

    Connector Implementations
  78. Widget Widget Widget Widget Preparer Fetch Requirements Resolver Resolver Services

    Connector Interfaces Connector Implementations
  79. Widget Widget Widget Widget Preparer Resolver Resolver Services Connector Interfaces

    Connector Implementations Batch requirements and pass them to resolvers
  80. Widget Widget Widget Widget Preparer Resolver Resolver Services Connector Interfaces

    Connector Implementations Call Services as effective as possible (Multi-GET,...)
  81. Widget Widget Widget Widget Preparer Resolver Resolver Services Connector Interfaces

    Connector Implementations Attach fetched data to Requirements and pass them back to the preparer
  82. Widget Widget Widget Widget Preparer Resolver Resolver Services Connector Interfaces

    Connector Implementations Distribute fetched data to the widgets that required it
  83. public function collect() {
 return [
 new EntityRequirement(
 'account',
 Account::class,


    ['id' => $this->request->get('id')]
 ),
 ];
 }
  84. Request Cache

  85. Multi-GET

  86. Futures

  87. Data dependencies within a widget

  88. public function collect() {
 yield [
 new EntityRequirement(
 'account',
 Account::class,


    ['id' => $this->request->get('id')]
 ),
 ];
 
 yield [
 new ServiceRequirement(
 'scienceDisciplines',
 AccountService::class,
 'getScienceDisciplines',
 ['account' => $this->account]
 )
 ];
 }
  89. Assembling the tree

  90. Profile Publications Publication Publication Publication AboutMe LeftColumn Image Menu PHP

    Backend Request Response Institution
  91. Widget Requirement

  92. var TodoApp = React.createClass({
 getInitialState: function () {
 return {items:

    […]};
 },
 render: function () {
 return (
 <div>
 <h3>TODO</h3>
 <TodoList items={this.state.items} />
 </div>
 );
 }
 });
  93. class PublicationKeywordSearch {
 
 public $publications;
 public $publicationListItems = [];


    
 public function collect() {
 yield [
 serviceRequirement(
 'publications',
 PublicationService::getCall()->getByKeywords(
 ['virology', 'cancer'], 10, 0
 )
 )
 ];
 foreach ($this->publications as $publication) {
 yield new WidgetRequirement(
 'publicationListItems',
 PublicationItem::CLASS,
 [ 'publicationId' => $publication->getId() ]
 );
 }
 }
 }
  94. class PublicationItem {
 
 public $publicationId;
 public $publication;
 
 public

    function collect() {
 yield new RequestDataRequirement('publicationId');
 yield [
 new EntityRequirement(
 'publication',
 Publication::class,
 ['id' => $this->publicationId]
 )
 ];
 }
 }
  95. Profile Publications Publication Publication Publication AboutMe LeftColumn Image Menu Institution

  96. Getting the data to React.js

  97. public function getData() {
 return [
 'key' => 'value',
 'other'

    => 'data',
 'number' => 42,
 'subComponent' => $this->subComponent,
 'someArray' => [1, 2, 3],
 'subComponentList' => [ $this->items[0], $this->items[1] ]
 ];
 }
  98. {
 "ParentComponent-1234": {
 "component": "ParentComponent.jsx",
 "id": "ParentComponent-1234",
 "data": {
 "key":

    "value",
 "other": "data",
 "number": 42,
 "subComponent": "SubComponent",
 "someArray": [1, 2, 3],
 "subComponentList": [ "ListItem-444", "ListItem-555"]
 }
 },
 "SubComponent": {
 "component": "SubComponent.jsx",
 "id": "SubComponent",
 "data": { "boolValue": true }
 },
 "ListItem-444": {
 "component": "ListItem",
 "id": "ListItem-444",
 "data": { "title": "444s title“ }
 },
 "ListItem-555": {
 "component": "ListItem",
 "id": "ListItem-555",
 "data": { "title": "555s title" }
 }
 }
  99. var React = require('react');
 var SubComponent = require('SubComponent');
 var ListItem

    = require('ListItem');
 
 module.exports = React.createClass(
 {
 displayName: 'ParentComponent',
 render: function () {
 var items = [];
 
 for (var key in this.props.subComponentList) {
 if (this.props.subComponentList.hasOwnProperty(key)) {
 items.push(
 <li>
 <ListItem componentId={this.props.subComponentList[key]}/>
 </li>
 );
 }
 }
 
 return (
 <div className="{this.props.key}">
 <h1>{this.props.other} Hello PHP {this.props.number}</h1>
 <SubComponent componentId={this.props.subComponent} />
 <ul>{items}</ul>
 </div>
 );
 }
 }
 );
  100. var React = require('react');
 
 module.exports = React.createClass(
 {
 displayName:

    'ListItem',
 render: function () {
 return (
 <div>
 {this.props.title}
 </div>
 );
 }
 }
 );
  101. GraphQL http://graphql.org/

  102. PHP Backend React Frontend GraphQL

  103. Server side rendering

  104. SEO

  105. Better user experience

  106. Several approaches

  107. http://pecl.php.net/package/v8js V8js

  108. Request HTML Preparer libV8 React PHP process Data array Rendered

    HTML string
  109. NodeJS proxy

  110. Request HTML Preparer nodeJS Proxy React PHP process Data JSON

    Rendered HTML string
  111. NodeJS service

  112. Request HTML Preparer nodeJS service PHP process Data JSON Rendered

    HTML string React
  113. Whoa

  114. This looks awfully complicated to debug

  115. None
  116. None
  117. Benefits

  118. Enables developers to only focus on their components

  119. Rapid prototyping

  120. Easier Refactoring

  121. Easy re-using of components

  122. Error Handling

  123. Profile Publications Publication Publication Publication AboutMe LeftColumn Image Menu Institution

  124. Profile Publications Publication Publication Publication AboutMe LeftColumn Image Menu EXCEPTION

    Institution
  125. Profile Publications Publication Publication Publication LeftColumn Image Menu Institution

  126. Experiments (A/B Testing)

  127. Feature toggles

  128. Profile Publications Publication Publication Publication AboutMe LeftColumn Image Menu Institution

  129. Profile Publications Publication Publication Publication AboutMeNew LeftColumn Image Menu Institution

  130. Caching of Components

  131. Profile Publications Publication Publication Publication AboutMe LeftColumn Image Menu <esi:include

    src="..." /> Institution
  132. Load components asynchronously

  133. Profile Publications Publication Publication Publication AboutMe LeftColumn Image Menu <div

    id="placeholder"></div> <script>loadWidget('/aboutMe', function(w) { w.render({ replace : '#placeholder' }); })</script> Institution
  134. Conclusion?

  135. Think about your architecture

  136. Refactor and make it better continuously

  137. Frontend and backend are part of the same application

  138. Don't rewrite your whole codebase in one go

  139. https://joind.in/talk/1f1aa

  140. http://twitter.com/BastianHofmann http://lanyrd.com/people/BastianHofmann http://speakerdeck.com/u/bastianhofmann mail@bastianhofmann.de