Components

Next we will start writing out our components. This will serve as a good introduction to React.

Initialize

  1. First we will add the needed dependencies for developing a React application:
    yarn add react
    
  2. And the needed developer dependencies for React development (with TypeScript):
    yarn add -D @types/react tslint-react
    
    The package @types/react gives us type definitions for React and tslint-react allows us to use TSLint to lint our React components.

Configuring for React

First we will configure TypeScript to work with JSX by adding the following line to our tsconfig.json:

{
    "compilerOptions": {
        "jsx": "react",
        // Rest of the compiler options
    }
    // Rest of the config file
}

As we are not using another transformation step setting jsx to the value of react will emit the actual JavaScript after compilation.


To use tslint-react we add the following lines to the file tslint.json:

{
    "extends": ["tslint-react"], // This will allow us to use tslint-react-specific rules
    "rules": {
        "jsx-no-lambda": false, // This disallows the definition of functions inside a React Component's render-function
        // The rest of the rules
        "quotemark": [true, "single", "jsx-double"] // We added "jsx-double" here to denote that in JSX one should use double quotation marks.
    }
}

Button

We will start with the simplest component that utilizes all the tools we need for most components, a Button, so go ahead and create a file Button.tsx (the extension defines the file as a TypeScript-file that has JSX in it) in the folder components:

import * as React from 'react';

interface IButtonProps {
    click(): void;
    readonly text: string;
}

const Button: React.StatelessComponent<IButtonProps> = ({ click, text }) => (
    <input className="btn" type="submit" onClick={() => click()} value={text} />
);

export default Button;

In the first row

import * as React from 'react';

we import all the functionalities provided by React under the name React (* as React), including the ability to write JSX (those things that look like HTML).


On the third to sixth rows

interface IButtonProps {
    click(): void;
    readonly text: string;
}

we define an interface to denote the properties (or props for short) our component accepts (and in this case needs). click() defines a function, which will be known as click inside our Button and as we have only defined that it takes no arguments, we also tell the compiler that we don't care if it returns anything, just that it can be called, using the return type of void. readonly text: string on the other hand defines a readonly (an immutable property) called text inside our Button, that is of the type string.

Interfaces are shapes we define, meaning that we do not care what the actual implementation is, just that it has those types of values with those names. They cannot be instantiated as such and thus cannot contain default values like classes.


On the eighth to tenth rows

const Button: React.StatelessComponent<IButtonProps> = ({ click, text }) => (
    <input className="btn" type="submit" onClick={() => click()} value={text} />
);

we define a constant (an immutable variable) called Button which is of the type React.StatelessComponent, meaning it is a React component, which does not have an internal state, but only props of type IButtonProps. Stateless components in React only need to define their render-method and using an ES6 arrow function and a destructuring assignment we can return JSX with our props already defined as simple variables (in this case "click" and "text"). The actual return here is a simple HTML input element with a class of btn (in React you define classes with the property "className"), a type of submit, an onClick-handler that will simply call the click-property and a value of text (in submit buttons the value is the text in the button).

You need to surround JSX with parentheses.


And finally on the twelfth row

export default Button;

we export our Button as the default export of the module.

TodoComponent

Next we will define a component to visualize our Todo-class from the previous section, creating a file called TodoComponent.tsx in the components-folder:

import * as React from 'react';
import Todo from '../common/Todo';

export interface ITodoComponent {
    readonly todo: Todo;
    setDone(i: number): void;
}

const TodoComponent: React.StatelessComponent<ITodoComponent> = ({ todo, setDone }) => (
    <div className="todo">
        <input
            className="todo__checkbox"
            type="checkbox"
            checked={todo.done}
            onChange={() => !todo.done && setDone(todo.id)}
        />
        <span className="todo__number">{todo.id}:</span>
        <span className="todo__title">{todo.title}</span>
    </div>
);

export default TodoComponent;

which is mostly very similar to our Button. The biggest differences here are the second import

import Todo from '../common/Todo';

which imports our Todo-class using a relative path (the TypeScript compiler will look for the file relative to the current file) and the second property in our interface

    setDone(i: number): void;

which defines a function called setDone that takes one argument, which is a number.

Loader

Next we implement our third and simplest component, called a Loader, in a file called Loader.tsx in the components-directory

import * as React from 'react';

const Loader: React.StatelessComponent<undefined> = () => (
    <div className="loader">
        <div className="loader__spinner" />
    </div>
);

export default Loader;

which uses all previously introduced tools, except this time we have defined the props it receives as undefined, meaning that it does not take any props at all.

PageNotFound

Lastly we create a page to be shown whenever user enters a URL that is not found (a 404), called PageNotFound in the components-directory

import * as React from 'react';

const PageNotFound: React.StatelessComponent<undefined> = () => (
    <div className="page-not-found">
        404 - page not found
    </div>
);

export default PageNotFound;

which is again a very simple component, very similar to Loader.

Alternatives

Below you can find alternatives to React, although I would suggest React unless you have specific needs, which other frameworks solve better, as it also allows for mobile development with React Native.

  • AngularJS, possibly the most popular framework after React
  • elm, a functional alternative
  • Cycle.js, a functional reactive alternative

results matching ""

    No results matching ""