I like the programming language TypeScript, and recently, I’ve been blogging about this language. Earlier, I’ve been blogging about programming in Angular with TypeScript. The time has come, and I’ll start a short series on programming in React.js with TypeScript.
The React.js library (a.k.a. React) was created by a Facebook engineer Jordan Walke in 2013, and today it has 1300 contributors and 130K stars on GitHub! According to Stack Overflow Developer Survey of 2019, it’s the second most popular JavaScript library (jQuery remains the most broadly used library), and in this blog series, I’ll show how to start developing web apps in React using TypeScript. React is not a framework but a library responsible for rendering views in the browser (think of the letter V in the MVC design pattern).
The main player of React is a component, and the UI of a web app consists of components having parent-child relations. But if Angular takes control of the entire root element of the Web page, React allows you to control a smaller page element (e.g. a div) even if the rest of the page was implemented with any other framework or in pure JavaScript.
You can develop React apps either in JavaScript or in TypeScript and deploy them using tools like Babel and Webpack, and without further ado let’s start by writing the simplest version of the Hello World app using React and JavaScript; we’ll switch to TypeScript a bit later.
Developing the simplest web page with React
I’ll show you two versions of a very simple web page written with React and JavaScript. Each of these pages renders Hello World, but if the first version uses React with no additional tooling, the second version will engage Babel.
In the real-world apps, a React app is a project with configured dependencies, tools and the build process, but to keep things simple, our first web page will have just a single file index.html, which loads the React library from CDN.
<!DOCTYPE html> <head> <meta charset="utf-8"> <script crossorigin src="https://unpkg.com/react@16/umd/react.development.js"> <1> </script> <script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"> <2> </script> </head> <body> <div id="root"></div> <3> <script > const element = React.createElement('h1', <4> null, <5> 'Hello World'); <6> ReactDOM.render(element, document.getElementById('root')); <7> </script> </body> </html>
1. Loading the React package from CDN
2. Loading the ReactDOM package from CDN
3. Adding the div with the id “root”
4. Creating the h1 element using createElement() function
5. We don’t send any data (props) to the h1 element
6. The text of the h1 element
7. Rendering the h1 inside the div
The processes of declaring the page content (React.createElement()) and rendering it to the browser’s DOM (ReactDOM.render()) are decoupled, and the former is supported by the API offered by the React object, while the latter is done by ReactDOM. Accordingly, we loaded these two packages in the heasd section of the page.
In React, all component’s UI elements have to be wrapped in one container, and this web page has a div element with the ID root that serves as such container for the content rendered by React. In the script, we prepare the element to render using React.createElement(), and then invoke ReactDOM.render() that finds the element with the root ID and renders it there.
In Chrome, right-click on Hello World and select the menu Inspect. It’ll open the Dev Tools showing the div with the h1 element inside.
The method createElement() has three arguments: the element, its props (data to be passed to the element) and content. In this case, we didn’t need to provide any props (think attributes) and used null here; I’ll explain what props are for in another blog. The content of h1 is “Hello World”, but it can contain child elements (e.g. ul with nested li elements), which could be created with the nested createElement() calls.
Open the file index.html in your browser, and it’ll render the text Hello World as shown next.
Invoking createElement() on the page that has only one element is fine, but for the page that had dozens of elements, this would become tedious and annoying. React allows you to embed the UI markup into the JavaScript code, which looks like HTML, but is JSX. Let’s see how our Hello World page could look like if we used JSX (note const myElement ) instead of invoking createElement().
<!DOCTYPE html> <head> <meta charset="utf-8"> <script crossorigin src="https://unpkg.com/react@16/umd/react.development.js"></script> <script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script> <script src="https://unpkg.com/babel-standalone/babel.min.js"></script> <!-- 1 --> </head> <body> <div id="root"></div> <script type="text/babel"> // <2> const myElement = <h1>Hello World</h1>; // <3> ReactDOM.render( // <4> myElement, document.getElementById('root') ); console.log(myElement); // <5> </script> </body> </html>
1. Adding Babel from CDN
2. The type of the script is text/babel
3. Assigning a JSX value to a variable
4. Initiating the rendering of myElement to the div
5. Monitoring the JavaScript object that was rendered
This app renders the same page as seen in the screenshot above, but it’s written differently. The JavaScript code has embedded string <h1>Hello World!<h1> that looks like HTML to you, but it’s actually JSX. Browsers can’t parse this, so we need a tool to turn JSX into a valid JavaScript. Babel to the rescue!
The <head> section has an additional <script> tag that loads Babel from the CDN. Also, I changed the type of our script to text/babel, which tells Babel to transform the content of this <script> tag into JavaScript.
We wouldn’t use CDN for adding Babel to a Node-based project as we did in the code above, but for demo purposes, it suffices. In the Node-based apps, Babel would be installed locally in the project and it would be a part of the build process.
The next screenshot shows the browser’s console open. Babel converted the JSX value to a JavaScript object that was rendered inside the div, and we printed this object in the console.
Now that you have a fair understanding of how the very basic pages that use React, let’s switch to Node-based projects and component-based apps and see some tooling that React developers use in the real world.
Generating and running a new React-TypeScript app with create-react-app
If you want to create a React app that includes a transpiler and a bundler, you’d need to add configuration files to your app, and this process is automated by the command-line interface (CLI) called create-react-app (see https://www.npmjs.com/package/create-react-app). This tool generates all required configuration files for Babel and Webpack, so you can concentrate on writing your app instead of wasting time configuring tooling. To install the package create-react-app globally on your computer, run the following command in the Terminal window:
npm install create-react-app -g
Now you can generate either a JavaScript or a TypeScript version of the app. To generate the TypeScript app, run the command create-react-app followed by the app name and the –typescript option:
create-react-app hello-world --typescript
In a minute or so, all required files will be generated in the directory hello-world and the project dependencies will be installed. In particular, it installs the following React packages:
* react – a JavaScript library for creating user interfaces
* react-dom – React package for working with the DOM
* react-scripts – scripts and configurations used by create-react-app
Besides the above packages, the CLI installs Webpack, Babel, TypeScript, their type definition files, and other dependencies. To launch the generated web app, switch to the directory hello-world and run npm start, which in turn runs react-scripts start. Webpack will bundle the app and webpack-dev-server will serve the app on localhost:3000 as shown in the next screenshot.
For bundling, Webpack uses the file webpack.config.js located in the directory node_modules/react-scripts/config.
The good part is that if you generated the project with create-react-app, it’ll recompile the code, rebuild the bundles, and re-render the UI. This functionality is provided by the Webpack Dev Server. The UI of this app tells us to edit the file src/App.tsx (tsx is for TypeScript + JSX), which is the main TypeScript file of the generated app. Open the directory in VS Code, and you’ll see the project files as shown in the next screenshot.
The source code of your app is located ins the src directory, and the public directory is for the assets of your app that shouldn’t be included in the app bundles. For example, your app has thousands of images and needs to dynamically reference their paths, and the directory public is for files that don’t require any processing before deployment.
The file index.html contains an element <div id=”root”>, which serves as a container of the generated React app. You won’t find any <script> tags for loading the React library code there; they’ll be added during the build process when the app’s bundles are ready.
You can run the app and open the Chrome Dev Panel under the Elements tab to see the runtime content of index.html.
The file serviceWorker.ts is generated just in case you want to develop a Progressive Web App (PWA) that can be started offline using cached assets. We are not going to use it in our sample apps.
As you see, some of the files have an unusual extension .tsx. If we’d be writing the code in JavaScript, the CLI would generate the app file with the extension .jsx (not .tsx).
JSX and TSX
The draft of the JSX specification offers the following definition: “JSX is an XML-like syntax extension to ECMAScript without any defined semantics. It’s NOT intended to be implemented by engines or browsers”.
JSX stands for JavaScript XML. It defines a set of XML tags that can be embedded inside the JavaScript code. These tags can be parsed and turned into regular HTML tags for rendering by the browser, and React includes such a parser. The next screenshot shows the Babel’s REPL with a sample JSX.
On the left, we selected the preset react and pasted a sample code from the JSX spec. This preset means that we want to turn each JSX tag into React.createElement() invocation. The sample code should render a dropdown with a menu containing three menu items. On the right, you see how the JSX was parsed into JavaScript.
Every React app has at least one component, which is called a root component, and our generated app has only the root component App. The file with the code of the function App has the name extension .tsx, which tells the TypeScript compiler that it contains JSX. But just having the extension .tsx is not enough for tsc to handle it: you need to enable JSX by adding the jsx compiler option. Open the file tsconfig.json, and you’ll find there the following line:
"jsx": "preserve"
The jsx option only affects the emit stage – type checking is unaffected. The value preserve tells tsc to copy the JSX portion into the output file changing its extension to .jsx, because there will be another process (e.g. Babel) that will be parsing it. If the value would be react, tsc would turn the JSX tags into React.createElement() invocations as seen in the above screenshot on the right.
In the next blog, I’ll introduce two types of React components and what the component’s state is about. If you want to learn TypeScript quickly, get our book TypeScript Quickly.
I believe vue.js got fusion of angular & react plus learning curve is short compare to both. Only downside compare to react will be corporate level of acceptance for vue. Are you moving away from angular? Good to know your thoughts.
> Are you moving away from angular?
It’s like asking, “Are you moving away from Phillips screwdriver?” All web frameworks are tools to create an app for the user. I don’t remember hearing from any user “I don’t like this app because it’s developed with the framework XYZ”.
IMO, Angular is the best for developing enterprise apps. It has everything needed for developing any web app. The learning curve is a little higher than with Vue and is comparable with the equivalent React.js-based set of tools. But if your team develops in Angular, the requirements for the qualification of the programmers is lower: just know Angular. React is good for smaller teams with higher average qualification where developers like to experiment with different packages. Vue is trying to take the middle ground between Angular and React. So far, it’s easiest to learn but this may change with the release of Vue 3 next year.
If you ask my opinion, use any of the three, but don’t mix them in the same app.
Thanks for your reply. All three got good resources and mixing them in one project will be close to self-destruction (so point noted).
So asking your opinion on Dart won’t be out of your wheel zone. You were an advocate of language after Adobe let go very productive Flex technology. Google is back with a new framework Flutter for mobile & web development (hummingbird framework) using Dart. Just like flex you can do single-page app & mobile development from one single codebase ( flex code can run on mobile using Adobe Air runtime..old times). Do you see similarities to Flex? Again, your helpful opinion matters.
Thanks,
Kavin
Hi Yakov, I have been following you online since early Adobe Flex (good ‘ol) days.
I have been working on Angular for quite some time now. Any specific reason to choose React with Typescript and not JS (Ecma)?
Thanks,
Hemang
I wrote about why use TyoeScript here https://yakovfain.com/2018/09/10/why-program-in-typescript
It remains the same for any JS framework.