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

React Amsterdam: Migrating safely to React

Jamis Charles
April 16, 2016
880

React Amsterdam: Migrating safely to React

Part 2 of my "migrating to React" talk

Jamis Charles

April 16, 2016
Tweet

Transcript

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

    View Slide

  2. View Slide

  3. UI Engineer
    Send Money San Jose, CA

    View Slide

  4. Back

    View Slide

  5. 2014

    View Slide

  6. C++
    XML Markup

    View Slide

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

    View Slide

  8. View Slide

  9. • too many abstraction layers
    • low confidence
    • difficult state bugs (currency codes mismatched
    etc)
    Pain

    View Slide

  10. • V1: Just ship it
    • Maintainability is low priority
    • Complexity rises
    What happened?

    View Slide

  11. by Rich Hickey
    Clojure
    Simple Made Easy

    View Slide

  12. Speed
    Time
    Easy

    View Slide

  13. Speed
    Time
    Simple

    View Slide

  14. Speed
    Time
    Easy Simple

    View Slide

  15. “Simple → predictable → Reliable”

    View Slide

  16. View Slide

  17. View Slide

  18. 1 feature →

    View Slide

  19. View Slide

  20. View Slide

  21. View Slide

  22. • React simplifies the view (fewer files)
    • Quick win
    • Push it to prod
    • Learn & evaluate
    Lessons learned

    View Slide

  23. Beyond the view

    View Slide

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

    View Slide

  25. • Backbone Router + custom routing logic
    • complex
    • difficult to track url -> code
    • good opportunity
    Routing Layer

    View Slide

  26. /request
    Routing
    /send

    View Slide

  27. /request
    Routing
    /send

    View Slide

  28. /request
    Routing
    /send

    View Slide

  29. /request
    Routing
    /send

    View Slide

  30. /request
    Routing
    /send

    View Slide

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

    View Slide

  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
    }
    });

    View Slide

  33. View Slide

  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(


    {/* Flow entry points */}




    , document.getElementById('react-transfer-container'));

    View Slide

  35. /request
    Routing
    /send

    View Slide

  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;

    View Slide

  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;

    View Slide

  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;

    View Slide

  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;

    View Slide

  40. /request
    Routing
    /send

    View Slide

  41. /request
    Routing
    /send

    View Slide

  42. /request
    Routing
    /send

    View Slide

  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;

    View Slide

  44. import React from 'react';
    import * as routeUtil from '../utils/routeHelper';
    let SendContainer = React.createClass({
    propTypes: {
    params: React.PropTypes.object.isRequired
    },
    render() {
    return
    }
    });
    export default SendContainer;

    View Slide

  45. • Url → code is easy now
    • Reduced complexity
    • Good migration path for a give url
    Routing Layer

    View Slide

  46. • Backbone Models & Collections
    • complex
    • Most of our state pain comes from here
    Data Layer

    View Slide

  47. Migrate 1 feature?

    View Slide

  48. View Slide

  49. new feature

    View Slide

  50. • Larger time investment
    • Greater risk
    • More testing / QA needed
    What about old data?

    View Slide

  51. View Slide

  52. View Slide

  53. View Slide

  54. Optimize for future
    change

    View Slide

  55. – Michael Feathers
    “You have to build a barrier between yourself
    and the framework.”

    View Slide

  56. – Jamis Charles
    “Use as much vanilla JS as possible.”

    View Slide

  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
    },

    View Slide

  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
    },

    View Slide

  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
    });

    View Slide

  60. In Conclusion

    View Slide

  61. Solve real problems

    View Slide

  62. View Slide

  63. Thank you

    View Slide

  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

    View Slide

  65. @jamischarles
    #reactamsterdam

    View Slide

  66. View Slide