Ben Petersen's Software Development blog

React is a UI framework created by Facebook and Instagram, it's all JS and HTML, focusing around resuable components, data flow, and state.
code | 2017-05-25
Tags: Software Front-End React

What is React? How could it be easier to extend or maintain?

  • Reusable components (Ex: FancyCheckbox, SelectMenu, CommentList)
  • View logic is unified with markup
  • Data flows one direction
  • No specific language

React Components at their simplest

  • React.createClass is used to create components. Here, it’s to make a list of comments.
  • Props are passed on to the Comment component
  • Can pass this.props to components, but it’s harder to refactor.
  • Views and logic are JS and HTML with strings
Fancy Checkbox - Simple example

Props

Consume props only when you have to, Transfer props where possible. No point in consuming a prop you don’t use in this component.

Controlled Components

  • Data validation via events and state
  • Predicable state changes b/c explicit mutations
Controlled Components - Simple example

Reusable Components

  • Extract portions of components when it makes sense.
  • Can group components together for sharable pieces. Custom selects, buttons. Props are main driver and higher order functions aide in reuse.
    • IconComponent
    • IconTextComponent
  • Re-use all the things!

Stateless Functional Components

  • Functions or Classes are both components, take props as input, and return elements as output.
  • Compare previous exmaple to quoteParentStateFunctions.js
  • Doesn’t depend on state, always returns the same result given the same arument.
  • Use stateless components when it only has a render function and doesn’t modify state.
  • Useful for testing and reduces bugs b/c it doesn’t modify state/props, only consumes them
Stateless Functional React Component

Biggest Gotchas w/ React

  • Setting up a project
    • Grab a project on github to start
    • Or use rnplay.org (jump in and test ideas out, no need to invest in npm installs)
  • .bind(this) is crucial inside context changes: .ajax, forEach, etc
  • state vs props and when to use “Pure Functions”
Examples and things to notice
  • One direction data flow (parent to child)
  • Views are simple HTML with strings (no domain specific language).
  • Avoid JSX if possible,less verbose than HTML and friendlier to any text editor. See React/Redux is Inferior
  • Explicit mutation (operations that write to state)
  • Parent components require Keys for child components

Simple Quote Example - Reusable Components

function formatThousands(num){ return num > 999 ? (num/1000).toFixed(1) + 'k' : num } function formatDecimal(num){ return Math.round(num100)/100; } var SymbolTable = React.createClass({ //suplying key to component, not to the container HTML render: function() { return ( ); } }); var FilterableSymbolTable = React.createClass({ getInitialState: function() { return { symbols: [], symbolsToSearch: '' }; }, componentDidMount: function() { //split symbols and search this.props.symbolsToSearch.split(',').forEach(function(symbol){ this.searchForSymbol(symbol); }.bind(this)) }, searchForSymbol: function(symbol){ $.ajax({ url: "http://dev.markitondemand.com/MODApis/Api/v2/Quote/jsonp", data: {symbol: symbol}, dataType: 'jsonp', cache: false, success: function(data) { this.setState({ symbols: this.state.symbols.concat([data]) }); }.bind(this) }); }, render: function(){ return (
); } }); ReactDOM.render( //symbol used as this.prop.symbol , document.getElementById('content') );

Parent State Example

Ideas to notice: state holds symbolsToSearch and symbols, which is passed through FilterableSymbolTable and SymbolTable

function formatThousands(num){ return num > 999 ? (num/1000).toFixed(1) + 'k' : num } function formatDecimal(num){ return Math.round(num100)/100; } var SymbolRow = React.createClass({ render: function() { return ( ); } }); var SymbolTable = React.createClass({ render: function() { var rows = []; this.props.symbols.forEach(function(symbol){ rows.push(); }.bind(this)); return ( ); } }); var FilterableSymbolTable = React.createClass({ getInitialState: function() { return { symbols: [], newSymbol: '', symbolsToSearch: ['MSFT', 'AAPL'] }; }, componentDidMount: function() { this.state.symbolsToSearch.forEach(function(symbol){ this.searchForSymbol(symbol); }.bind(this)) }, searchForSymbol: function(symbol){ $.ajax({ url: "http://dev.markitondemand.com/MODApis/Api/v2/Quote/jsonp", data: {symbol: symbol}, dataType: 'jsonp', cache: false, success: function(data) { this.setState({ symbols: this.state.symbols.concat([data]) }); }.bind(this) }); }, handleSubmit: function(e) { e.preventDefault(); var allItems = this.state.symbolsToSearch.concat([this.state.newSymbol]); this.setState({ symbolsToSearch: allItems }); this.searchForSymbol(this.state.newSymbol); }, refreshSymbols: function(e){ e.preventDefault(); this.setState({ symbols: [] }); this.componentDidMount(); }, onChange: function(e){ this.setState({ newSymbol: e.target.value }) }, render: function(){ return ( ); } }); ReactDOM.render( //symbol used as this.prop.symbol , document.getElementById('content')

Parent State Functions using Props Example

Ideas to notice: props passed into SymbolRow

function formatThousands(num){ return num > 999 ? (num/1000).toFixed(1) + 'k' : num } function formatDecimal(num){ return Math.round(num*100)/100; } //Pure functions, aka return the same result given the same arugements. var SymbolRow = function(props){ return ( ); } var SymbolTable = function(props){ var rows = []; props.symbols.forEach(function(symbol){ rows.push(); }.bind(this)); return ( ); } var FilterableSymbolTable = React.createClass({ getInitialState: function() { return { symbols: [], newSymbol: '', symbolsToSearch: ['MSFT','AAPL','IBM','GOOG','FB','YHOO'] }; }, componentDidMount: function() { this.state.symbolsToSearch.forEach(function(symbol){ this.searchForSymbol(symbol); }.bind(this)) }, searchForSymbol: function(symbol){ $.ajax({ url: "http://dev.markitondemand.com/MODApis/Api/v2/Quote/jsonp", data: {symbol: symbol}, dataType: 'jsonp', cache: false, success: function(data) { this.setState({ symbols: this.state.symbols.concat([data]) }); }.bind(this) }); }, handleSubmit: function(e) { e.preventDefault(); //TODO: put into correct format {name: this.state.newSymbol} var allItems = this.state.symbolsToSearch.concat([this.state.newSymbol]); this.setState({ symbolsToSearch: allItems }); this.searchForSymbol(this.state.newSymbol); }, refreshSymbols: function(e){ e.preventDefault(); this.setState({ symbols: [] }); this.componentDidMount(); }, onChange: function(e){ this.setState({ newSymbol: e.target.value }) }, render: function(){ return ( ); } }); ReactDOM.render( //symbol used as this.prop.symbol , document.getElementById('content') );

Articles to Read

My React examples

Paradigms to know about

  • Reactive Programming and less manual wiring of events, code is closer to requirements aka Cycle.js
  • Observable streams, instead of state and stores like in Redux or Flux aka RxJS