=========== JSX and ES6 =========== TypeScript is a JavaScript superset with a compiler that enforces the types. It's also, though, one of those sexy new JavaScript flavors that implement "ES6"...actually, a family of modern JavaScript standards for more productive programming. When combined with other tooling, it also supports JSX, React's sorta-templating system, but with TypeScript semantics. We glazed over the ES6 and JSX (that is, TSX) in previous steps. Let's take more of a look. Cleanup ======= The previous steps added some stuff to show their topics. Let's clean up a little bit. Let's change ``App.test.tsx`` back to two simple tests: .. code-block:: jsx import { shallow } from 'enzyme'; import * as React from 'react'; import * as ReactDOM from 'react-dom'; import App from './App'; it('renders without crashing', () => { const div = document.createElement('div'); ReactDOM.render(, div); ReactDOM.unmountComponentAtNode(div); }); it('renders the heading', () => { const wrapper = shallow(); expect(wrapper.find('h1').text()).toBe('Hello React'); }); Also, our component in ``App.tsx``: .. code-block:: jsx import * as React from 'react'; class App extends React.Component { public render() { return (

Hello React

); } } export default App; Make sure the test runner is still running and watching. You can, though, shutdown the ``start`` task. We don't need it regenerating the bundle and updating the browser, duplicating what's happening in the Jest process. Our two tests pass. Let's see some ES6 and TSX. Classes and Fields ================== As you can see, this component is using React's support for ES6 classes. Our ``App`` component extends ``React.Component`` which has a constructor that initializes a bunch of stuff. We'll see functional components later. Let's do another approach at extracting the hardwired string from the ``

``. The ``render`` method can, of course, have scope. Let's define the label there: .. code-block:: jsx public render() { const label = 'Hello React'; return (

{label}

); } The ``const`` is used because we never intend to re-assign the label. Our tests pass, so this change worked fine. We can also move the ``label`` up to the class label as a field: .. code-block:: jsx class App extends React.Component { public label = 'Hello React' public render() { return (

{this.label}

); } } We had to change the ``

`` to use ``this.label``, to get the value off the instance. Arrow Functions =============== ES6 introduced small, inline anonymous functions called "arrow functions". The are incredibly useful and have come to dominate frontend frameworks. Let's see them in action for click handlers. We'll start by showing something that doesn't work until an arrow function saves the day. We'll first do an inline click handler that displays a static string. Note that JSX (and thus, TSX) map certain HTML attributes into first-class names, such as ``onClick`` and ``className``, in its grammar, thus letting us assign an expression (with ``{}``) instead of a string::

{this.label}

But this fails. Why? The expression is immediately evaluated, rather than run when the event is fired. We need a way to assign something that will be executed *later*, when the event is fired. Arrow functions to the rescue! Try this instead::

alert('Hello World')}>{this.label}

What does this change do? It stores a function which is created on the fly and stored "anonymously" in that scope. The ``()`` means this arrow function needs no arguments. (It's actually passed an event, which we'll use in later steps.) The function body is one line, so we don't need curly braces for a block. .. _bossy-tslint: This is actually valid TypeScript, and would compile and run, but our picky style linter complains. In React, defining functions on the fly is expensive (when you're doing hundreds in a loop) and the TSLint community decided to frown on that by default. We can override the default, though. Edit ``tslint.json`` to contain: .. code-block:: json { "extends": ["tslint:recommended", "tslint-react", "tslint-config-prettier"], "linterOptions": { "exclude": [ "config/**/*.js", "node_modules/**/*.ts" ] }, "rules": { "jsx-no-lambda": false } } Restart your ``start`` script to get the linter to pick up the change. Everything compiles fine and clicking on the ``

`` in the browser produces an alert. Move To a Method ================ Inline handlers aren't so smart, as they aren't easily testable. Plus, bossy TSLint doesn't like them (for performance reasons.) Let's move the handler to a component method: .. code-block:: jsx class App extends React.Component { public label = 'Hello React' public handleClick () { alert('Hello World'); } public render() { return (

{this.label}

); } } We referenced ``this.handleClick`` but we didn't call it. React will call it later, when we actually click. Clicking on the heading works well, so let's remove the ``"jsx-no-lambda": false`` rule from ``tslint.conf`` and restart the ``start`` script. Let's have the alert display the label by changing it to ``alert(this.label);``. Uh-oh. Clicking on the heading produces a mile-long traceback in the JavaScript console. The traceback mentions ``HTMLUnknownElement``. And that's the problem: the ``this`` in the ``handleClick`` method isn't the component instance, it is event. This is a chronic problem in React programming, causing the ``.bind`` syntax. Arrow functions, though, get the correct ``this``. We could change the handler to the following::

this.handleClick}>{this.label}

...but we're back to the bossy TSLint complaint. Instead, we can bind the arrow function to the component: .. code-block:: typescript public handleClick = () => { alert(this.label); } Look at that freaky approach! Instead of a method, we are binding a dynamic function to a class property. (Discussion below about the downsides.) JSX === React brought innovation to the concept of templating languages by extending JavaScript itself. Your templating is mixed directly into your JavaScript file and component. TSX is the TypeScript flavor of JSX, with file extensions ending in ``.tsx``. The easiest way to see TSX in action? Go to your ``

`` and try to add ``class=""``. TypeScript itself has JSX/TSX support in the compiler and gives a compiler error:: Property 'class' does not exist on type 'DetailedHTMLProps, HTMLHeadingElement>'. Also, the IDE refuses to autocomplete on ``class``. It does, though, autocomplete on ``className``, the JSX/TSX equivalent. Accepting the autocomplete shows that the IDE fills in ``{}`` for an attribute value instead of double-quotes. What's the difference? A double-quote contains a regular string, whereas brackets contain JavaScript expressions, which we saw above. Note About Arrow Functions ========================== Arrow functions look great on classes but behind the scenes they don't really do what you think. Purists have pointed out the flaws (mockability, subclassing, performance.) And yet, they remain a very popular solution to binding in React and similar systems.