React Amsterdam: Migrating safely to React

4387c963a177feda12b08de5bcc8b855?s=47 Jamis Charles
April 16, 2016
690

React Amsterdam: Migrating safely to React

Part 2 of my "migrating to React" talk

4387c963a177feda12b08de5bcc8b855?s=128

Jamis Charles

April 16, 2016
Tweet

Transcript

  1. Migrating safely to React (part 2) @jamischarles React Amsterdam 2016

  2. None
  3. UI Engineer Send Money San Jose, CA

  4. Back

  5. 2014

  6. C++ XML Markup

  7. Server {Dust.js} Client Kraken.js BB

  8. None
  9. • too many abstraction layers • low confidence • difficult

    state bugs (currency codes mismatched etc) Pain
  10. • V1: Just ship it • Maintainability is low priority

    • Complexity rises What happened?
  11. by Rich Hickey Clojure Simple Made Easy

  12. Speed Time Easy

  13. Speed Time Simple

  14. Speed Time Easy Simple

  15. “Simple → predictable → Reliable”

  16. None
  17. None
  18. 1 feature →

  19. None
  20. None
  21. None
  22. • React simplifies the view (fewer files) • Quick win

    • Push it to prod • Learn & evaluate Lessons learned
  23. Beyond the view

  24. 1. View layer 2. Routing layer 3. Data layer The

    pieces
  25. • Backbone Router + custom routing logic • complex •

    difficult to track url -> code • good opportunity Routing Layer
  26. /request Routing /send

  27. /request Routing /send

  28. /request Routing /send

  29. /request Routing /send

  30. /request Routing /send

  31. require('backboneSubroute'); module.exports = Backbone.SubRoute.extend({ routes: { '': 'showTransfer', ':type(/:action)': 'showTransfer'

    }, […]
  32. require('backboneSubroute'); module.exports = Backbone.SubRoute.extend({ showView: function (options) { if (options.name)

    { this.loadScripts(options); } historyModel.addPath(options.name); }, getPath: function (scriptName) { // getPath code }, loadScripts: function (options) { // loadScripts code }, cleanView: function () { // cleanView code } });
  33. None
  34. // React Components... import MainContainer from '../containers/main'; import RequestContainer from

    '../containers/request'; import SendContainer from '../containers/send'; import BuyContainer from '../containers/buy'; ReactDOM.render( <Router history={history}> <Route path='/myaccount/transfer/' component={MainContainer}> {/* Flow entry points */} <Route path={'request(/:action)'} component={RequestContainer} /> <Route path={'send(/:action)'} component={SendContainer} /> <Route path={'buy(/:action)'} component={BuyContainer} /> </Route> </Router>, document.getElementById('react-transfer-container'));
  35. /request Routing /send

  36. import React from 'react'; import indexView from '../index'; let SendContainer

    = React.createClass({ propTypes: { params: React.PropTypes.object.isRequired }, componentDidMount() { this.showBBView(); }, componentDidUpdate() { this.showBBView(); }, // will load and show a Backbone view. showBBView() { let type = 'send'; let action = this.props.params.action || 'recipient'; // gets content and renders it into the DOM. indexView.navigate(type, action); }, render() { return null; } }); export default SendContainer;
  37. import React from 'react'; import indexView from '../index'; let SendContainer

    = React.createClass({ propTypes: { params: React.PropTypes.object.isRequired }, componentDidMount() { this.showBBView(); }, componentDidUpdate() { this.showBBView(); }, // will load and show a Backbone view. showBBView() { let type = 'send'; let action = this.props.params.action || 'recipient'; // gets content and renders it into the DOM. indexView.navigate(type, action); }, render() { return null; } }); export default SendContainer;
  38. import React from 'react'; import indexView from '../index'; let SendContainer

    = React.createClass({ propTypes: { params: React.PropTypes.object.isRequired }, componentDidMount() { this.showBBView(); }, componentDidUpdate() { this.showBBView(); }, // will load and show a Backbone view. showBBView() { let type = 'send'; let action = this.props.params.action || 'recipient'; // gets content and renders it into the DOM. indexView.navigate(type, action); }, render() { return null; } }); export default SendContainer;
  39. import React from 'react'; import indexView from '../index'; let SendContainer

    = React.createClass({ propTypes: { params: React.PropTypes.object.isRequired }, componentDidMount() { this.showBBView(); }, componentDidUpdate() { this.showBBView(); }, // will load and show a Backbone view. showBBView() { let type = 'send'; let action = this.props.params.action || 'recipient'; // gets content and renders it into the DOM. indexView.navigate(type, action); }, render() { return null; } }); export default SendContainer;
  40. /request Routing /send

  41. /request Routing /send

  42. /request Routing /send

  43. import React from 'react'; import * as routeUtil from '../utils/routeHelper';

    let SendContainer = React.createClass({ propTypes: { params: React.PropTypes.object.isRequired }, componentDidMount () { this.showBBView(); }, componentDidUpdate() { this.showBBView(); }, // will load and show a Backbone view. showBBView() { let type = 'send'; let action = this.props.params.action || 'recipient'; // gets content and renders it into the DOM. routeUtil.getIndexView().navigate(type, action); }, render() { return null; } }); export default SendContainer;
  44. import React from 'react'; import * as routeUtil from '../utils/routeHelper';

    let SendContainer = React.createClass({ propTypes: { params: React.PropTypes.object.isRequired }, render() { return <SendComponent /> } }); export default SendContainer;
  45. • Url → code is easy now • Reduced complexity

    • Good migration path for a give url Routing Layer
  46. • Backbone Models & Collections • complex • Most of

    our state pain comes from here Data Layer
  47. Migrate 1 feature?

  48. None
  49. new feature

  50. • Larger time investment • Greater risk • More testing

    / QA needed What about old data?
  51. None
  52. None
  53. None
  54. Optimize for future change

  55. – Michael Feathers “You have to build a barrier between

    yourself and the framework.”
  56. – Jamis Charles “Use as much vanilla JS as possible.”

  57. import $ from ‘jquery'; import Backbone from ‘backbone'; export default

    Backbone.View.extend({ el: 'form', events: { 'keyup #note': 'resizeTextAreaField', 'blur #note': 'hideTextAreaCounters' }, // Resize text area as user types resizeTextAreaField: function (event) { var count = this.countTextContent(); var newHeight = this.getIdealTextAreaHeight(count); var newRows = this.getRowsFromHeight(newHeight); $('#note').height(newHeight).attr('rows', newRows); }, // Update textarea counter with remaining character left hideTextAreaCounters: function (event) { // pseudo code },
  58. import $ from ‘jquery'; import Backbone from ‘backbone'; export default

    Backbone.View.extend({ el: 'form', events: { 'keyup #note': 'resizeTextAreaField', 'blur #note': 'hideTextAreaCounters' }, // Resize text area as user types resizeTextAreaField: function (event) { var count = this.countTextContent(); var newHeight = this.getIdealTextAreaHeight(count); var newRows = this.getRowsFromHeight(newHeight); $('#note').height(newHeight).attr('rows', newRows); }, // Update textarea counter with remaining character left hideTextAreaCounters: function (event) { // pseudo code },
  59. import $ from ‘jquery'; import Backbone from ‘backbone'; import *

    as ResizeUtil from 'utils/resizeTextareaUtil'; export default Backbone.View.extend({ el: 'form', events: { 'keyup #note': 'resizeTextAreaField', 'blur #note': 'hideTextAreaCounters' }, // Resize text area as user types resizeTextAreaField: ResizeUtil.resizeField, // Update textarea counter with remaining character left hideTextAreaCounters: ResizeUtil.hideTextArea });
  60. In Conclusion

  61. Solve real problems

  62. None
  63. Thank you

  64. Sources • React Rally talk: https://www.youtube.com/ watch?v=mrtwImsEq5s • Moving from

    Require to Webpack 
 https://www.paypal-engineering.com/ 2015/08/07/1450/ • http://www.infoq.com/presentations/Simple- Made-Easy
  65. @jamischarles #reactamsterdam

  66. None