Components

JSX

JSX is a popular way of defining markup in JavaScript for templating purposes in many libraries and frameworks. Most developers like JSX because it is a clearer representation of what will be produced. Others dislike it because they think it is mixing HTML into JavaScript. As of version 5.2.0, you can use JSX to define the template of a component's render function. Internally, this gets converted into a string template that the component render function expects. If you are one of those who do not like JSX, you can continue using template literals in your component as always. If you would prefer to use JSX, continue reading.

JSX provides better syntax highlighting than template literals, which are just strings. JSX also allows you to define partials and use them as custom tags in your component. This allows you to break a complex render function down into smaller, more manageable pieces.

Self-Closing Tags

Using JSX means you have a number of issues to be aware of. JSX is a dialect of XML. This means that your markup must follow many XML rules. HTML5 does not follow those rules. Note the following:

Self-closing tags must be terminated with a forward slash: <img src='myImg.png'> must be: <img src='myImg.png' /> . This is true for all self-closing tags: img, br, hr, etc. Failure to properly terminate self-closing tags will result in an error at build time. Note that you can also give a self-closing tag a closing tag: <img src='myImg.png'></img> . Regardless of which method you choose to terminate a self-closing tag, the result will be a normal HTML5 self-closing tag.

// Template Literal // No need to close img tag: const listComponent = new Component({ element: '#list', render: (data) => html` <li> <img src='${ data.img.src }'> </li> ` }) // JSX // img tag must be closed with forward slash: const listComponent = new Component({ element: '#list', render: (data) => ( <li> <img src={ data.img.src } /> </li> ) })

Creating a Project with JSX

It's easy to create a project with support for JSX. When creating your project with the chui command line tool, just provide the flag -x as one of the arguments:

# Create project that supports JSX: chui -n "JSX Project" -x -t navigation

Doing this will add everything needed to convert JSX into string templates for ChocolateChip-UI components. After creating your project, open its dev folder, then its component or template file. You'll notice that at the top there's a line:

import {h} from '../src/utils/h'

Wherever you define a component that uses JSX, you'll need to also import ChocolateChip-UI's h method. When you create a project for JSX with the -x flag, the chui CLI puts a modified .babelrc file in your project that tells Babel to use that imported h method to process the JSX.

JSX in Components

So, we have a project that supports JSX. Now lets create a new component that uses it. We'll pretend that we create a file called "list.js" in our project's dev folder. At the top of the file we put (the path needs to match wherever you've put the file in relation of the dev folder's src folder:

import {h} from '../src/utils/h'

Now that we have imported the h method, we can write JSX in our component. Generally you want to enclose the JSX inside parens:

// list.js import {h} from '../src/utils/h' const list = new Component({ element: '#list', render: (fruit) => ( <li> <h3>{fruit.name}</h3> <aside> <span class='price'>{fruit.price}</span> </aside> </li> ) })

Capturing the Loop Index

Just like with template literals, you can capture the loop index value and output it by using a second parameter in the component's render function:

const list = new Component({ element: '#fruits', state: new State(['Apples', 'Oranges', 'Bananas']), // Capture loop index for output: render: (fruit, idx) => ( <li> <h3>{idx + 1}: {fruit}</h3> </li> ) }) list.render()

Partials in JSX

Sometimes, as you're looping over an array of data, the loop instance object may have children that are arrays that you also need to loop over. This is fairly common. For instance, when outputting a list of recipes, each recipe could have its own list of ingredients and instructions. With template literals you can handle this in two ways: by using map on the child array, or by writing a helper function (partial) and passing the data to it. You can also do this with JSX. However, with the helper function JSX offers a twist. You can use the partial as a custom tag inside the parent's markup. OK, so lets look at how to do this. We'll start with map :

const list = new Component({ element: '#recipes', render: (recipe) => ( <li> <div> <h3>{recipe.name}</h3> <h4>Ingredients</h4> <ul> {recipe.ingredients.map(ingredient => <li>{ingredient}</li>)} </ul> <h4>Directions</h4> <ol> { recipe.directions.map(direction => <li>{ direction }</li>)} </ol> </div> </li> ) }) list.render(recipeData)

And here's a Codepen example:

See the Pen JSX-1 with Custom Tags V5 by Robert Biggs (@rbiggs) on CodePen.

The above JSX template works fine, printing out a list of ingredients and directions for each recipe. However, it is not easy to read. Using partials we can make this much cleaner. To create partials with JSX, you define a function that returns the markup you need. You can then use the name of that function as a custom tag in your JSX. Because of JSX syntax rules, custom tags must have the first letter capitalized. That means your partial's function name must be capitalized as well, as if it were a class.

So, because we want to output a list with the partial, we pass the recipe object to our partial's function. This leads us to a problem with representing that function as a custom tag: the function is represented as a tag and has no parens for passing arguments. To get around this, you need to pass you function's arguments as props on the custom tag. You do this in two ways:

The data you pass to the partial must be enclosed in curly braces. You use curly braces with a spread operator on the custom tag to pass it the function arguments: {...{recipe}} .

Let's start with the partials. Notice how there arguments are enclosed in curly braces:

const Ingredients = ({recipe}) => ( <ul> {recipe.ingredients.map(ingredient => <li>{ingredient}</li>)} </ul> ) const Directions = ({recipe}) => ( <ol> { recipe.directions.map(direction => <li>{ direction }</li>)} </ol> )

The above two methods -- Ingredients and Directions -- retrun a list of their data. To use these in our JSX template, we write them as tags with a forward slash. To pass the arguments to them, we use curly braces with a spread operator. This is identical to passing props to a React component.

const list = new Component({ element: '#recipes', render: (recipe) => ( <li> <div> <h3>{recipe.name}</h3> <h4>Ingredients</h4> <Ingredients {...{recipe}} /> <h4>Directions</h4> <Directions {...{recipe}} /> </div> </li> ) }) list.render(recipeData)

In the above example we terminated the custom tags with a forward slash. We could also have used an end tag. Both work the same Most people seem to prefer the sorter format:

<Ingredients {...{recipe}} /> // Or: <Ingredients {...{recipe}}></Ingredients>

Using partials as custom tags makes the template easier to read. You could store your template partials in external files and import them into your components. This makes it easy for you to reuse partials in multiple components and in other projects.

And here's a Codepen example of the above code:

See the Pen JSX-1 with Custom Tags V5 by Robert Biggs (@rbiggs) on CodePen.

JSX Attributes

This is the part that may trip you up. With template literals, dealing with attribute values is simple, just create the attribute/value pair as normal and add a dollar sign and curly braces for the part that needs to be dynamic:

<li data-goto='detail:${ data.guid }'>

In JSX you have to replace the entire attribute value. Also, and this is very important, you do not use quote around the property value. Doing so will prevent the code from being interpreted:

<li data-goto={`detail:${ data.guid }`}>

Default Attribute Names

In JSX there are certain properties that you have to modify to use. These are class as className , for as htmlFor and inline events needing to be camel cased:

<li className='special' onClick={doSomething()}>{data}<li>

Our h function bypasses this limitation so that you can use them in their normal html format:

<li class='special' onclick={doSomething()}>{data}<li>

Regarding inline events, we recommend you define your events using the component's actions property. This keeps your component markup leaner and gives you one place to deal with all user interactions in a component. Markup cluttered with styles and inline events is just messy. Don't do it. Use the actions and styles properties to organize your code into clearly separated areas of responsibility. Let your component's template be about rendering data exclusively. That way when you look at it, it will be easy to understand what it is outputting.

Limitations of JSX Markup

With template literals, you can create sibling components that get injected into the component's parent element:

// HTML: <ul class='list' id='list'></ul> // JavaScript: const list = new Component({ element: '#list', state: fruitStore, render: (fruit) => html` <li> <h3>${ fruit.name }</h3> </li> <h3>${ fruit.price }</h3> <li>` }) list.render()

With template literals the above code is valid and would output two sibling list items for each loop. This is not possible with JSX due to the XML syntax rules that it follows. Instead there must be a single root tag that owns all other tags as its children.

If you find you need to output a group of siblings, wrap them in a div or aside tag. Or see if you can solve your needs with a custom JSX tag.

About the Codepen Examples

You will notice that we use the Babel pragma: /** @jsx h */ before the JSX components in our pens. This is to let the Codepen Babel transpiler know to use the ChocolateChip-UI h function to process the JSX. When you create a project with the chui command line tool, it creates a .babelrc file configured to do this automatically for you, so you do not need to use the pragma in your code. Just make sure you always import the h method into whatever file is defining a template with JSX. The path to h will depend on the position of the file in your dev folder:

import {h} from '../src/utils/h'

If you get a JSX component doesn't render in the browser, open the console and look for errors. If you find ReferenceError: Can't find variable: h , this means that Babel couldn't find the h function in that file to transpile the JSX. Import the h function at the top of the file will solve this.

Performance

Using JSX introduces an extra step in converting a component's render template into DOM nodes. This means a very slight performance penalty when compared to using template literals. We ran a performance test 100 times to create 1,000 and then 10,000 list items. The results were:

Create Table Rows: 1,000 10,000 _______________________________________ Template Literals 55.4 0 730.79 JSX 83.46 854.05

The difference in milliseconds is fairly minimal and surely not perceptible to a human user. The JSX version is still much faster than the same test with Angularjs and React:

Create Table Rows: 1,000 10,000 _______________________________________ Angular v4.1.2 156.75 1256.52 React v15.5.4 183.93 1026.02