Category: Hello React and TypeScript
Part 7: Get Up and Running with #React and #TypeScript
The “Get Up and Running with React and TypeScript” series is made up of posts from chapters in my book “Hello React and TypeScript“. If you have questions, comments or corrections, please reach out to me in the comments or on Twitter @charleslbryant.
You can view the posts in this series on the Hello React and TypeScript category page.
Component Composition
This sample gives a basic example of refactoring the Hello World application by composing the UI with modular components.
Source Code
https://github.com/charleslbryant/hello-react-and-typescript/releases/tag/0.0.7
src/helloworld.tsx
/// <reference path="../typings/tsd.d.ts" /> import * as React from 'react'; import HelloForm from 'helloform'; import HelloContent from 'hellocontent'; export default class HelloWorld extends React.Component<any, any> { constructor(props: any){ super(props); this.state = { name: this.props.defaultName }; this.handleChange = this.handleChange.bind(this) } public handleChange(event: any) : void { this.setState({ name: event.target.value }); } public render() { return ( <div> <HelloForm name = { this.state.name } handleChange = { this.handleChange } /> <HelloContent name = { this.state.name } /> </div> ); } }
The HelloWorld
component is updated to compose the same UI as the previous example using two modular components, HelloForm
and HelloContent
.
import * as React from 'react'; import HelloForm from 'helloform'; import HelloContent from 'hellocontent';
To compose with components the components you want to compose have to be in scope. To do this we import the components. HelloForm
and HelloContent
are imported by using the import
statement with the from
value being the name of the component.
public render() { return ( <div> <HelloForm name = { this.state.name } handleChange = { this.handleChange } /> <HelloContent name = { this.state.name } /> </div> ); }
The actual composition occurs in the render
method. We add the HelloForm
and HelloContent
components. Notice that the name of the components start with uppercase to differentiate them from HTML elements. Each of the components accept some properties and we pass them with a syntax that is similar to defining HTML attributes.
By composing UIs in this manner we move from an imperative style of building UIs to a declarative one. Instead of defining every element and attribute we want to use in the UI we delegate the definition to a modular reusable component.
Since the modular components are reusable we can compose multiple UIs with them. We can compose with components developed by other teams. We get to focus on the unique aspects of our domain and delegate other lower level concerns to modular components.
src/helloform.tsx
/// <reference path="../typings/tsd.d.ts" /> import * as React from 'react'; export default class HelloForm extends React.Component<any, any> { constructor(props: any){ super(props); } public render() { return ( <div> <input value={ this.props.name } onChange={ e => this.props.handleChange(e) } /> </div> ); } }
Here we have a new component responsible for the collecting user input for our tiny application. By now this code should be familiar. We just moved the input element from the HelloWorld
component and encapsulated it in this new component.
For this simple example we are storing all of our components in one folder. As your application grows you may want to use a folder structure that makes the number of component files more manageable. When you are at the point of doing this you will have to address the reference path for the TypeScript typings. It will become a maintenance issue having to keep the path in sync as you move components and build new folder structures, but we won’t go into that just yet.
src/hellocontent.tsx
/// <reference path="../typings/tsd.d.ts" /> import * as React from 'react'; export default class HelloContent extends React.Component<any, any> { constructor(props: any){ super(props); } public render() { return ( <div> Hello { this.props.name }! </div> ); } }
This is a component responsible for displaying the hello message. Again, this component is a result of encapsulating this section of the DOM out of the HelloWorld
component.
Stateless Components
One interesting observation about these components is that they are stateless. They don’t hold any state and they rely on a parent component to pass props
to it in order to do its work. This includes event handlers and data as you can see in the sample code.
When possible using stateless components are preferred in React. They help to improve performance because they lessen the amount of processing that React has to do with the component.
Part 6: Get Up and Running with #React and #TypeScript
The “Get Up and Running with React and TypeScript” series is made up of posts from chapters in my book “Hello React and TypeScript“. If you have questions, comments or corrections, please reach out to me in the comments or on Twitter @charleslbryant.
You can view the posts in this series on the Hello React and TypeScript category page.
Accept User Input
This sample gives an basic example of accepting user input.
Source Code
https://github.com/charleslbryant/hello-react-and-typescript/releases/tag/0.0.6
src/helloworld.tsx
/// <reference path="../typings/tsd.d.ts" /> import * as React from 'react'; export default class HelloWorld extends React.Component<any, any> { constructor(props: any){ super(props); this.state = { name: this.props.defaultName }; } public handleOnChange(event: any) : void { this.setState({ name: event.target.value }); } public render() { return ( <div> <div> <input onChange={ e => this.handleOnChange(e) } /> </div> <div> Hello { this.state.name }! </div> </div> ); } }
The significant changes here are we removed the button and handleOnClick
method. We also added a text box and a handleOnChange
method to handle changes as a user adds input to the text box.
public handleOnChange(event: any) : void { this.setState({ name: event.target.value }); }
This is a new method to handle the onChange event. In the method we are calling this.setState
and updating the value of name
in this.state
to the value of the target element passed in the event.
public render() { return ( <div> <div> <input onChange={ e => this.handleOnChange(e) } /> </div> <div> Hello { this.state.name }! </div> </div> ); }
Here we added an input element and set its default value to this.props.name
. We also bound the text box’s onChange event to handleOnChange
method.
With these changes we have implemented a unidirectional data flow.
- When the user enters something in the text box it triggers the
onChange
event. - The
onChange
event is handled by thehandleOnChange
method. - The
handleOnChange
method updates the value ofname
inthis.state
and triggers a re-render of the component withthis.setState
. this.setState
ends in a call to therender
method that updates the name in our “Hello” message.
State is only changes as the result of an event. The Hello message is no bound to an external model state and can only be updated as a result of an event being triggered by user input. This is different than two way binding or bi-directional data flow where changes in a model can also update the state of a view.
Unidirectional Data Flow (UDF)
event > event handler > state > render
Components are representations of the state of a view over time. As events are triggered over time they update state and re-render the component with the new state. The flow can be seen as a stream of events that flow in one direction that eventually update component state causing a component to re-render. If you know about CQRS, event streaming, or stream processing, there are similar concepts in each. UDF is a redundant theme in learning React, hence a redundant theme in this book.
The sample is a simple naive example because we aren’t dealing with external or persisted data. The scope of the example makes it a little hard to understand UDF. In the example we don’t have to worry about updating an external store.
If you are having trouble understanding UDF, when you learn about Flux it will makes more sense. The Flux architecture helps you visualize data flow in a circular one way round trip. Even though it may be hard to see UDF within the context of a single component the same event flow is used to accomplish UDFin React whether within a single component, a Flux architecture, or using Relay (another Facebook library). When you get into Flux or other data flow patterns or libraries, UDF will be expanded to add additional concepts into the data flow.
UDF vs Bi-directional Data Flow
The important thing to notice about UDF is that we aren’t attempting to create a complex bi-directional view binding with some external model. We are binding to the state modeled within a component with no dependency or complex mapping to some external data model. The component is responsible for expressing its own state, updating its state, passing properties to its child components, and re-rendering itself and children when state changes as the result of some event.
If we were to use a bi-directional binding to an external model, we would not know why state is being updated. Any number of views could have the same binding to the same model. With bi-directional binding a change to a view or model could cause updates to multiple models or views and it becomes hard to understand the data flow, especially when you are trying to solve a Sev1 incident.
If you’d like to know more about UDF, there is a lot about it online that can be found with a simple search. Actually, the original MVC pattern is an example of UDF. It was distorted when it moved to web clients. If you’d like to dig into the theory behind React and UDF, you can research Functional Reactive Programming – https://en.wikipedia.org/wiki/Reactive_programming.
Part 5: Get Up and Running with #React and #TypeScript
The “Get Up and Running with React and TypeScript” series is made up of posts from chapters in my book “Hello React and TypeScript“. If you have questions, comments or corrections, please reach out to me in the comments or on Twitter @charleslbryant.
You can view the posts in this series on the Hello React and TypeScript category page.
Component Interactivity
This sample gives an basic example of using adding interactivity to a component.
Source Code
https://github.com/charleslbryant/hello-react-and-typescript/releases/tag/0.0.5
src/helloworld.tsx
/// <reference path="../typings/tsd.d.ts" /> import * as React from 'react'; export default class HelloWorld extends React.Component<any, any> { constructor(props: any){ super(props); this.state = { name: this.props.defaultName }; } public handleChange(event: any) : void { this.setState({ name: "Charles" }); } public render() { return ( <div> Hello { this.state.name }! <button name = "Update" onClick = { e => this.handleOnClic(e) } >Update</button> </div> ); } }
To add interactivity we:
- added an element for a user to interact with
- created a method to handle an event triggered by user interaction
- bound the new element’s onClick event to the new event handler method
public handleOnClick(event: any) : void { this.setState({ name: "Charles" }); }
This is a new method to handle the click event. We expect callers of this method to send the event as an argument so we defined the argument as type any
so we can accept any event. We could define a specific or generic event type and restrict the argument to that type. We also define the method as returning void
or nothing.
In the method we are calling this.setState
and updating the value of name
. When we callthis.setState
it causes the component to re-render with the new state.
return ( <div> Hello { this.state.name }! <button name = "Update" onClick = { e => this.handleOnClick(e) } >Update</button> </div> );
We are adding a new HTML element, button (remember that HTML elements start with lowercase letter). The interesting bit is that we are binding the element’s onClick
event to the handleOnClick
method. To bind the event handler with the event we are using the new ES6 arrow function expression to simplify function context binding. Notice that the event handler is camelCased which is consistent with JavaScript style.
Function Context Binding
In the end, React is just plain JavaScript. The React Team has resisted the urge to add a lot of magic and have made strides to remove magic to reduce coupling. Magic is the encapsulated work that is hidden behind abstractions. When a library does work behind the scenes without you knowing it, its magic. Reducing this hidden work helps to losen coupling and that is a good thing because it enables reuse. The React team believes our code shouldn’t have a lot of coupling to React.
One example of this, related to our use of the arrow function above, is function context binding. There was a time when React automatically bound functions to this
. If you aren’t a JavaScript developer there is a chance that you don’t know that this
in JavaScript is different from this
in C# or Java or self
in Ruby.
In some strongly typed languages, this
is bound to an object instance. In JavaScript this
is bound to the function it is called in. This causes a lot of confusion, but this decoupling of this from their parent function allows us to reuse functions outside of the parent, powerful and dangerous at the same time.
To get this function reuse we can define the context for a function and have this
represent what we want it to. In our example the arrow function is assigning this from the class HelloWorld
to thehandleOnClick
method. If we wanted, we could use this same method in say a GoodByeWorld
class and the arrow function could set the context of the handleOnClick
method.
Without the arrow function we would use JavaScripts bind
method to achieve the same effect. The arrow function is just some syntactic sugar for
onClick = { handleOnClick().bind(this) }
You can get more on arrow functions here https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions.
Part 4: Get Up and Running with #React and #TypeScript
The “Get Up and Running with React and TypeScript” series is made up of posts from chapters in my book “Hello React and TypeScript“. If you have questions, comments or corrections, please reach out to me in the comments or on Twitter @charleslbryant.
You can view the posts in this series on the Hello React and TypeScript category page.
Component Props and State
This sample gives an basic example of using props and state in your components.
Source Code
https://github.com/charleslbryant/hello-react-and-typescript/releases/tag/0.0.4
src/main.tsx
/// <reference path="../typings/tsd.d.ts" /> import * as React from 'react'; import * as DOM from 'react-dom'; import HelloWorld from './helloworld'; const root = document.getElementById('app'); class Main extends React.Component<any, any> { constructor(props: any){ super(props); } public render() { return ( <div> <HelloWorld defaultName='World' /> </div> ); } } DOM.render(<Main />, root);
The change to main.tsx is minor. Here is the one change.
return ( <div> <HelloWorld defaultName='World' /> </div> );
We are just passing defaultName
to the HelloWorld
component. This is doing exactly what you think it is, its setting the default value for who we are saying Hello to. Notice that this name is explicit in defining this input. It is a default value, the HelloWorld component can change this value and the assumption is that it may be changed.
Another thing to notice is the camelCasing.
All DOM properties and attributes (including event handlers) should be camelCased to be consistent with standard JavaScript style. https://facebook.github.io/react/docs/dom-differences.html
src/helloworld.tsx
/// <reference path="../typings/tsd.d.ts" /> import * as React from 'react'; export default class HelloWorld extends React.Component<any, any> { constructor(props: any){ super(props); this.state = { name: this.props.defaultName }; } public render() { return ( <div> Hello { this.state.name }! </div> ); } }
We made two changes to helloworld.tsx, but they are significant to the interactivity of our little application.
constructor(props: any){ super(props); this.state = { name: this.props.defaultName }; }
In the constructor we are setting the initial state for this component. this.state
is a plain JavaScript object. It is a mutable representation of the model for the view. this.state
is expected to change over time as events occur in the component. In this sample we are initializing this.state
with an object literal{ name: this.props.defaultName }
.
this.props.defaultName
was passed in from main.tsx. this.props
is also a plain JavaScript object. The difference being it is an immutable representation data used by the component. this.props
should not be changed and they are passed in by parent components. If you change props, they will be overwritten when the parent rerenders. Mutating props puts your component in an inconsisten state, so don’t do it.
return ( <div>Hello { this.state.name }!</div> );
The next change is to the return value of the render
method. We are using this.state.name
to set the name dispayed in the UI.
In this sample we use this.props
to initialize this.state
. We know that we want to update the name of who we say hello to, so we are using a state object to represent the name. If we didn’t want to update name, we could use props directly. For example
return ( <div>Hello { this.props.name }!</div> );
Using props like this is saying that we don’t expect this component to change the name. In fact, to make it explicit, we changed the name from defaultName
to name
. Also, main.txt
would have to be changed from passing defaultName
to name
. Using props means we expect the parent to be in control of changing the value of props. Using state means we expect the component to be in control of its own state.
Part 3: Get Up and Running with #React and #TypeScript
The “Get Up and Running with React and TypeScript” series is made up of posts from chapters in my book “Hello React and TypeScript“. If you have questions, comments or corrections, please reach out to me in the comments or on Twitter @charleslbryant.
You can view the posts in this series on the Hello React and TypeScript category page.
Components in Separate Files
This sample demonstrates how to split your components into multiple files. It is still just the simple display Hello World, but now it is modular and reusable.
Source Code
https://github.com/charleslbryant/hello-react-and-typescript/releases/tag/0.0.3
The HTML is still exactly the same as sample #2.
src/main.tsx
We only have two changes to explore the main.tsx file.
/// <reference path="../typings/tsd.d.ts" /> import * as React from 'react'; import * as DOM from 'react-dom'; import HelloWorld from 'helloworld';//Add new import const root = document.getElementById('app'); class Main extends React.Component<any, any> { constructor(props: any){ super(props); } public render() { return ( <HelloWorld />//Return our new HelloWorld component ); } } DOM.render(<Main />, root);
Let’s look at the differences.
import HelloWorld from 'helloworld';
We added a new import to import the HelloWorld component.
return ( <HelloWorld /> );
Instead of returning the markup directly, we are returning the HelloWorld component and delegating the rendering of the markup to this new component. By having the markup in a separate component we can add <HelloWorld />
multiple times and only have to change it in one place. We have a single point of truth for what the markup for Hello World should be and we can reuse it.
To use external components they have to be in scope, which is why we imported it. Another point to make is that a React component needs to have only one root element. If we were to add more markup or components here, we would have to wrap it in a parent element.
Example:
return ( <div> <HelloWorld /> <HelloWorld /> </div> );
This would display “Hello World” twice. Notice how we started the component name with an uppercase letter, React expects components to start with uppercase and DOM elements to start with lowercase.
src/helloworld.tsx
/// <reference path="../typings/tsd.d.ts" /> import * as React from 'react'; export default class HelloWorld extends React.Component<any, any> { constructor(props: any){ super(props); } public render() { return ( <div>Hello World!</div> ); } }
If you paid attention to the previous sample you will notice that this is almost exactly like the old main.tsx. We copied main.tsx to a new file called helloworld.tsx. We gave the component class a new name and we deleted the import for DOM. We don’t need to import DOM because we don’t need to call anything from React.DOM.
That was pretty easy so I don’t think that we need to review this code.
Part 1 & 2: Get Up and Running with #React and #TypeScript
The “Get Up and Running with React and TypeScript” series is made up of posts from chapters in my book “Hello React and TypeScript“. If you have questions, comments or corrections, please reach out to me in the comments or on Twitter @charleslbryant.
You can view the posts in this series on the Hello React and TypeScript category page.
If you haven’t heard, I have been writing a little book called “Hello React and TypeScript“. Its a simple book that chronicles the steps I took to learn how to develop a React application using TypeScript and ES6.
I’m going to post some of the chapters here on my blog. This will provide an easy reference for me because the chapters are really a reorganization of notes that I took as I learned writing React with TypeScript/ES6. It is my hope that these posts may be helpful for someone looking to learn.
I will post the chapters, but I won’t keep them in sync with the book. If you want the latest and greatest, please check out the free book.
To start this series off we will look at the code samples. In this first post we will look at two chapters: Setting Up Samples and Component Basics. If you haven’t used React or TypeScript, I recommend you actually try out the code to get a better feel for React and TypeScript. You can reach out to me in the comments below or on Twitter @charleslbryant.
You can view the posts in this series on the Hello React and TypeScript category page.
Setting Up Samples
https://charleslbryant.gitbooks.io/hello-react-and-typescript/content/SettingUpSamples.html
Requirements
All of the code samples have a couple requirements
- npm package manager (Node 5.2.0 used in development)
- IE 10+ or similar modern browser that supports the History API
This first sample is the source for the basic development environment. This includes the packages and automation that will be used in the samples.
Note – to get the latest version of packages and automation you should clone the repository from root, https://github.com/charleslbryant/hello-react-and-typescript.git . We will make updates as we move along with new samples so version 0.0.1 is only a starting point.
Source Code
https://github.com/charleslbryant/hello-react-and-typescript/releases/tag/0.0.1
Installing
To install a sample you need to run npm to get the required dependencies. You should open a console at the root path of the sample directory and run
npm install
Then
tsd install
These commands will install the required npm packages and TypeScript Typings.
Run the Sample
To run the samples, open a console at the sample directory and run
gulp
This will kick off the default gulp task to run all the magic to compile TypeScript, bundle our dependencies and code into one bundle.js file, and move all of the files need to run the application to a dist folder, open the index.html page in a browser, and reload the site when changes are made to source files.
Basic React Component
https://charleslbryant.gitbooks.io/hello-react-and-typescript/content/Samples/ComponentBasic.html
This is a very basic example of a single React component. We could make it even simpler, but this example is still basic enough to start with.
Source Code
https://github.com/charleslbryant/hello-react-and-typescript/releases/tag/0.0.2
src/index.html
<!DOCTYPE html> <html lang="en"> <head> <title>Hello World</title> <link rel="stylesheet" href="css/bundle.css"/> </head> <body> <div id="app"></div> <script src="scripts/bundle.js"></script> </body> </html>
If you don’t understand this, I recommend that you find an introduction to HTML course online.
The important part of this file is
. We will tell React to inject its HTML output to this div.
src/main.tsx
/// <reference path="../typings/tsd.d.ts" /> import * as React from 'react'; import * as DOM from 'react-dom'; const root = document.getElementById('app'); class Main extends React.Component<any, any> { constructor(props: any) { super(props); } public render() { return ( <div>Hello World</div> ; ); } } DOM.render(<Main />, root);
If you know JavaScript, this may not look like your mama’s JavaScript. At the time I wrote this ES6 was only 6 months old and this sample is written with ES6. If you haven’t been following the exciting changes in JavaScript, a lot of the syntax may be new to you.
This is a JavaScript file with a .tsx extention. The .tsx extenstion let’s the TypeScript compiler know that this file needs to be compiled to JavaScript and contains React JSX. For the most part, this is just standard ES6 JavaScript. One of the good things about TypeScript is we can write our code with ES6/7 and compile it as ES5 or older JavaScript for older browsers.
Let’s break this code down line by line.
/// <reference path="../typings/tsd.d.ts" />
The very top of this file is a JavaScript comment. This is actually how we define references for TypeScript typing files. This let’s TypeScript know where to find the definitions for types used in the code. I am using a global definition file that points to all of the actual definitions. This reduces the number of references I need to list in my file to one.
import * as React from 'react'; import * as DOM from 'react-dom';
The import
statements are new in JavaScript ES6. They define the modules that need to be imported so they can be used in the code.
const root = document.getElementById('app');
const
is one of the new ES6 variable declaration that says that our variable is a constant or a read-only reference to a value. The root
variable is set to the HTML element we want to output our React component to.
class Main extends React.Component<any, any> {
class
is a new declaration for an un-hoisted, stict mode, function defined with prototype-based inheritance. That’s a lot of fancy words and if they mean nothing to you, its not important. Just knowing that class
creates a JavaScript class is all you need to know or you can dig in athttps://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes.
Main
is the name of the class.
extends
says that the Main
class will be created as a child of the React.Component<any, any>
class.
React.Component<any, any>
is a part of the TypeScript typing definition for React. This is saying that React.Component
will allow the type any
to be used for the components state and props objects (more on this later). any
is a special TypeScript type that basically says allow any type to be used. If we wanted to restrict the props and state object to a specific type we would replace any
with the type we are expecting. This looks like generics in C#.
constructor(props: any) { super(props); }
The contructor
method is used to initialize the class. In our sample, we only call super(props) which calls the contructor method on our parent class React.Component
passing any props that were passed into our constructor. We are using TypeScript to define the props as any
type.
In additon to calling super
we could also initialize the state of the component, bind events, and other tasks to get our component ready for use.
public render() { return ( <div>Hello World</div> ); }
Maybe the most important method in a React component is the render
method. This is where the DOM for our component is defined. In our sample we are using JSX. We will talk about JSX later, just understand that it is like HTML and outputs JavaScript.
JSX is not a requirement. You could use plain JavaScript. We can rewrite this section of code as
public render() { return ( React.createElement("div", null, "Hello World") ); }
The render
method returns the DOM for the component. After the return
statement you put your JSX. In our sample, this is just a simple div that says Hello World. It is good practice to wrap your return expression in parenthesis.
DOM.render(<Main />, root);
Lastly, we call DOM.render
and pass Main
, the React component we just created, and root
, the variable containing the element we want to output the component to.
That’s it, pretty simple and something we can easily build upon.
My New Book: “Hello React and TypeScript”
So, I have been doing a deep dive into React and TypeScript and found it a little difficult to find resources to help me. I could find plenty of great resources on React and TypeScript separately. Just exploring the documentation and many blogs and videos for the two is great. Yet, resources that explore writing React applications with TypeScript was either old, incomplete, or just didn’t work for me for one reason or another. I have to admit that I haven’t done a deep search in a while so that may have changed.
After some frustration and keyboard pounding, I decided to just consume as much as I can about both individually and just get a Hello World example working. With the basics done I went slowly all the way to a full blown application. Since I was keeping notes on that journey, why not share them?
I was going to share them in a few blog posts, but I have been trying to do a book on GitBook for a while and this topic seemed like a good fit. Also, I enjoy digging into React and TypeScript so this book is probably something I can commit to, not like my other sorry book attempts.
My little guide book isn’t complete and still very rough. It may not be completed any time soon with the rapid pace of change for JavaScript, TypeScript and React. Also, I am thinking about moving from Gulp/Browserify to WebPack. I have only completed a fraction of the samples I want to do… so much still to do. Even though I don’t think it is ready for prime time, it is a public open source book so why not share it, get feedback, and iterate.
You can get the free book from GitBook
https://charleslbryant.gitbooks.io/hello-react-and-typescript/content/index.html
The source code for the samples in the book are on GitHub
https://github.com/charleslbryant/hello-react-and-typescript
If you don’t like the book let me know. If you find something wrong, bad practice or advice, incoherent explanations… whatever, let me know. If you like it let me know too, I can always use an ego boost :). Now I just have to convince myself to do some videos and talks… public speaking, bah :{
Enjoy!