JSX deep dive

@h6165

Abhishek Yadav

Co-organizer: Chennai.js

The agenda

JSX

  • The syntax
  • The idea/rationale
  • Interpolation
  • Custom elements, components
  • JSX conditionals
  • JSX loops  
  • JSX without React ?

 

JSX


// This should be counted as valid javascript

var el = <div>Hello World</div>;

The idea

So that -

=> We can write HTML syntax within Javascript

=> => That gets converted to equivalent real HTML when needed

JSX


// This should place the div within document

var el = <div>Hello World</div>;

ReactDOM.render(el, document)

The idea

JSX


<!-- A more sane example -->

<div id='root'></div>
<script type='text/babel'>
  const rootElement = document.getElementById('root')  


  const el = <div>Hello World</div>;
  ReactDOM.render(el, rootElement)

</script>

The idea

Create that Hello World element, 

insert it inside the root element

JSX


<!-- Just like this ? Jquery FTW !! -->

<div id='root'></div>
<script type='text/babel'>


  const el = $('<div>Hello World</div>')
  $('#root').html(el)

</script>

The idea

JSX


<!-- Or even plain Javascript -->

<div id='root'></div>
<script type='text/babel'>
  const rootElement = document.getElementById('root')


  rootElement.innerHTML = '<div>Hello World</div>'

</script>

The idea

JSX

The idea

Then why JSX ?

It seems to achieve the same goals as the older techniques

JSX

The rationale

The goal -

  • be a template (for React)
  • simplify composition (components) (for React)
  • no direct DOM manipulation (for React)

 

(The React vision, maybe)

JSX

As a template


<!-- A more sane example -->

<div id='root'></div>
<script type='text/babel'>
  const rootElement = document.getElementById('root')  
  const name = 'Abhi'

  const el = <div>Hello {name}</div>;
  ReactDOM.render(el, rootElement)

</script>

JSX

As a template

  • Templates (handlebars etc) are not always easy to compose.
  • We often want to build larger UI using smaller template fragments (Components)

JSX

As a template - composition


// We need something like this 
// (Incorrect syntax below)

  const Hello = <div> Hello {name} </div>;
  const Score = <div> Your score is {score} </div>


  const el = <div>
               <Hello />
               <Score />
             </div>


  ReactDOM.render(el, rootElement)


JSX

As a template - composition


// The following will work


  const Hello = () => <div> Hello {name} </div>
  const Score = () => <div> Your score is {score} </div>


  const el = <div>
               <Hello />
               <Score />
             </div>


  ReactDOM.render(el, rootElement)


A function with capitalized name becomes a React component

JSX

As a template - composition


// Even better


  const Hello = (props) => <div> Hello {props.name} </div>
  const Score = (props) => <div> Your score is {props.value} </div>


  const el = <div>
               <Hello name='Abhi' />
               <Score value='100' />
             </div>


  ReactDOM.render(el, rootElement)


All attributes passed to this component are its props

JSX

As a template - composition


// Even better


  const Hello = (props) => <div> Hello {props.children} </div>
  const Score = (props) => <div> Your score is {props.children} </div>


  const el = <div>
               <Hello> Abhi </Hello>
               <Score> 100 </Score>
             </div>


  ReactDOM.render(el, rootElement)


All child elements within this component are its props.children

JSX

As a template - composition


// Even better


  const Hello = (props) => <div> Hello {props.children} </div>
  const Score = (props) => <div> Your score is {props.children} </div>

  let data = { name: 'Abhi', score: 75 }

  const el = <div>
               <Hello> { data.name } </Hello>
               <Score> { data.score } </Score>
             </div>


  ReactDOM.render(el, rootElement)


Externally obtained data being used here

JSX

As a template - composition


// Even better


  const Hello = (props) => <div> Hello {props.children} </div>
  const Score = (props) => <div> Your score is {props.children} </div>

  const ScoreCard = (props) => { 
    <div>
       <Hello> { props.name } </Hello>
       <Score> { props.score } </Score>
    </div>
  }


  let data = { name: 'Abhi', score: 75 }
  let el = <ScoreCard {...data} />

  ReactDOM.render(el, rootElement)


The entire widget as a component, with data passed in using spread operator

JSX

As a template - composition - summary

  • A function with capitalized name becomes a React component
  • It can return Html tags or other custom components
  • All attributes passed to this component are its props
  • All child elements within this component are its props.children
  • The look and feel is almost like HTML. Just that we cant use the class property

JSX

React.createElement

  • All the JSX elements are converted into React.createElement calls
  • Babel does this conversion
  • This is also visible in the final source, in the browser

JSX

React.createElement

// JSX

var el = <div>Hello World</div>;
// Javascript

var el = React.createElement(
  "div",
  null,
  "Hello World"
);

Try in http://babeljs.io/repl

JSX

React.createElement

// JSX

<div id='foo'>
  <Hello> { props.name } </Hello>
</div>
// Javascript

React.createElement(
  "div",              // name in quotes
  { id: 'foo' },      // attributes
  React.createElement(
    Hello,            // Capitalized, no quotes
    null,
    " ",
    props.name,
    " "
  )
);
  • Custom components, like Hello here capitalized, and are not within quotes
  • Normal tags,  like div are within quotes
  • The attributes are passed as the second argument

JSX

JSX conditionals

// Conditionals in JSX
// The following does not work

let list = [];
<div>
  { 
    if (list.length == 0){
      <div> No items </div>
    }
    else {
      <div> {list.length} items </div>
    }
  }
</div>
  • What goes within JSX should be expressions - should evaluate to the expected value
  • 'JSX is just syntactic sugar for function calls and object construction' - React docs

JSX

JSX conditionals

// Conditionals in JSX
// The following works

let list = [];

<div>
  { 
    (list.length == 0) ? 
      <div> No items </div>
      :
      <div> {list.length} items </div>
  }
</div>
  • Ternary operators make expressions. Hence they work
  • This kind of code is common
  • Can be improved

JSX

JSX conditionals

// Conditionals in JSX
// The following works

const render = (list ) => {
  let none = <div> No Items</div>
  let itemList = <div> Items list </div>
  
  if (list.length == 0) return none;
  return itemList;
}
  • Its better to keep conditionals out of JSX interpolations

JSX

JSX conditionals

// Conditionals in JSX
// The following works

let None = () => <div> No Items</div>
let ItemList = () => <div> Items list </div>

const render = (list ) => {  
  if (list.length == 0) return <None/>;
  return <ItemList />;
}
  • And even better - use smaller custom components

JSX

JSX loops

// Loops in JSX
// The following does not work -


<div>
{
    for (var i=0; i < numrows; i++) {
        <span> Item - {i}</span>
    } 
}
</div>
  • Loops also don't work this way
  • Reason is the same - JSX is just syntactic sugar for function calls and object construction

JSX

JSX loops

// Loops in JSX
// The following works -


<div>
  { list.map( item => <span>Item - {item} </span> ) }
</div>
  • Use map function calls instead
  • key is also needed

JSX

JSX loops

// Loops in JSX
// The following works -

const render = () => {
    var rows = [];
    for (var i = 0; i < numrows; i++) {
        rows.push(<span key={i}>Item - {i} </span>);
    } 
    return (<div>{rows}</div>);
}
  • Or pre-generate the contents

JSX

JSX outside React

  • Since JSX is well specified () it can be implemented by libraries other than React
    • https://facebook.github.io/jsx/
  • The jsx-transform project tries to decouple JSX from React, for use with the mercury framework
    • https://github.com/alexmingoia/jsx-transform
    • https://github.com/Raynos/mercury

JSX

React Virtual DOM

  • React maintains an in-memory copy of the DOM - the Virtual DOM
  • Changes are applied to this copy, and are passed on to the real DOM when needed
  • Changes are applied as diffs. When there are no diffs, the DOM doesn't change.
  • This is a great optimization, and makes React perform much better than traditional templates

</ppt>

JSX

By Abhishek Yadav