Tag Archives: typescript

React, Redux, and Typescript – Why, What and How

This article covers adding Redux to an existing React application.

Redux is one of those technologies where you get introduced to it, and you think: this seems overly complex to solve such a simple problem. Quite often, this is, in fact, the case. I once read a post (which I cannot find) by Dan Abramov where he said a similar thing himself. Redux is a state manager, and if you’re using it for React, React does have facilities to manage its own state, so you may not need Redux.

In fact, from what I’ve seen, I’d say you’re better leaving it until you know you need Redux.

Why

So, how will you know when you need Redux?

Well, you’ll know because you’ll raise some state, and suddenly realise that you’ve raised it into a component that has no business managing that state. My specific example was trying to manage user permissions.

Imagine the following menu structure:

Layout.tsx
	NavMenu.tsx
		NavItem (React-Strap)
		LoginMenu.tsx (accesses the DB to get user info)

I needed to store a user permission, and conditionally display a menu option (NavItem); these are held in a LoginMenu component. This meant that my state would need to be in NavMenu.tsx – but that’s a strange place for the state regarding a user to live. Additionally, other parts of the application would need access to this, and so it’s time for a state manager.

What

Okay, we’ve talked about why you might want to add Redux. Let’s see, exactly what Redux is. Essentially, there are three concepts to Redux. Before I continue with my second rate explanation, I would strongly suggest you jump over to Dave Ceddia’s blog. If you’re trying to do this in Typescript, then come back afterwards – otherwise, stay there, there’s nothing I can tell you that he doesn’t cover in this article.

Actions

An action is simply an object that contains a property called type. It can contain other objects, too, and is used to send information from your application into the Redux Store.

Reducers

Reducers are the engine of Redux. They accept an action, and the existing state of the application, and they return a new state.

Store

The store holds the current application state. You cannot change this directly, but through an action.

How

(In this section, I’ll include some imports and file names – I’ll talk about project structure towards the end, and the imports and filenames will make sense then)

Let’s imagine that your application is a game, where you can move a character left and right; your application state might look like this:

export interface IStore = {
    position: 0
}

We’ll also need to create the store, which we can do in the same code file:

Store.tsx

import { reducer } from '../State/Reducer';
import { createStore } from 'redux';

export interface IStore {
    position: number;
}

const store = createStore(reducer);
export default store;

Okay, so we have a state: we said that actions are the only things that can affect state (in fact we said through an action): let’s see what an action might look like:

export const MOVE = 'MOVE'

interface MoveAction {
    type: typeof MOVE
}

This would be sufficient, at least, this is all Redux needs; however, we need to know which way to move, etc. Convention seems to be to add a payload property; let’s see what that might look like:

Actions.tsx

export const MOVE = 'MOVE'
export interface Message {
    user: string
    message: string
    timestamp: number
  }
  
interface MoveAction {
    type: typeof MOVE
    payload: Message
}
    
export type ActionTypes = MoveAction;

I’ve used a generic Message – you could make this specific to your action, but this sort of approach means that your messages are consistent across actions.

So, now we have a store (somewhere to keep the state), and an action something to indicate that we wish to update the state. However, looking at the action, it doesn’t seem to do too much updating… In fact, it’s just a message – it could even be just a string. We now need the final piece of the jig-saw: the reducer takes the action and updates the state; let’s see what that might look like:

Reducer.tsx

import { InitialState } from './Store';
import { ActionTypes, MOVE } from './Actions';

export function reducer(state = InitialState, action: ActionTypes) {  
    console.log (action);
    switch (action.type) {
      case MOVE:
        return {
            ...state,
            position: state.position + parseInt(action.payload.message)
        }
        
      default:
        return state;
  
    }
    
}

There’s quite a lot here: (we’ll come back to InitialState shortly). Let’s go through a piece at a time.

The first thing we’re doing is checking the type parameter:

    switch (action.type) {
      case MOVE:

In a real world situation, there would be many options: you’re unlikely to have a single action, so the switch statement is necessary.

Remember earlier, we defined the action as MOVE:

export const MOVE = 'MOVE'

Which enables us to check for MOVE, rather than the magic string “MOVE”.

Inside the MOVE block, we’re accessing the payload:

      case MOVE:
        return {
            ...state,
            position: state.position + parseInt(action.payload.message)
        }

The reducer must be a pure function: that is, it accepts and returns data, but it does not change anything; as a result, we’re returning a new version of the state that was passed in. We’re setting the new state to have a position which is based on the current position, but we’re not changing the state.

This code will crash if the message is set to “qwerty” (so if you’re doing this sort of thing yourself, you should do it better than I have!)

Finally, the default: block simply returns the same state that it was given; i.e. the state remains unchanged.

Initial State and Project Structure

I said we’d come back to initial state. In the reducer, we have the following:

export function reducer(state = InitialState, action: ActionTypes) {  

We have to define a starting state for the store; and you can do that like this:

Store.tsx

export const InitialState: IStore = {
    position: 0
}

Before we move onto the application changes, let’s quickly talk about where this all goes. The frustrating answer is, it’s up to you; however, I found a structure like this quite useful, as it keeps all the Redux plumbing in a single place:

Plugging this into your app

So far, we’ve created a lot of code, but it’s been completely separate from your React application. Plugging it in is actually quite trivial. Let’s start with Index.tsx; you’ll need to import your reducer:

import { reducer } from './State/Reducer';

In the render function, you’ll then need to add the store into the DOM:

ReactDOM.render(
  <Provider store={store}>
    <BrowserRouter basename={baseUrl}>
      <App />
    </BrowserRouter>
  </Provider>,
  rootElement);

We can then access the store inside any component by simply referencing the Store.tsx:

import store from '../../State/Store';
import { MOVE } from '../../State/Actions';

And then calling the dispatch function:

            store.dispatch({
                type: MOVE,
                payload: {
                    user: user.name,
                    message: "1",
                    timestamp: new Date().getTime()
                }
            });

We can also get the state by using this:

store.getState();

Connecting the State

This works okay, but there is an easier way; you can use the Redux Connect function. Essentially, instead of exporting the React class, you instead export a wrapper for it. Before that, though, you need to work out what you’re trying to map. You’ll need to split your props into three groups:

1. Props from the store that you want in your component
2. Props that you want to be passed into your component
3. Props from the store that are actually functions; that is, dispatch functions

You would then rewrite your component like this:

import { connect } from 'react-redux';
interface StoreProps {
   position: number;
}
interface OwnProps {
   ...
}
interface DispatchProps {
   ...
}

type Props = OwnProps & StoreProps & DispatchProps;
interface IState {
   ...
}
class GameComponent extends Component<Props, IState> {
   ...

Notice that you’re no longer exporting the GameComponent class. Instead, you add the following:

function mapStateToProps(state: IStore) {
  return {
    position: state.position
  };
}
export default connect(mapStateToProps)(GameComponent);

This allows you to expose only the properties relevant to the component, but not the properties that you take from the Redux store.

References

https://blog.logrocket.com/why-use-redux-reasons-with-clear-examples-d21bffd5835/

https://daveceddia.com/redux-tutorial/

https://daveceddia.com/access-redux-store-outside-react/

https://redux.js.org/recipes/usage-with-typescript

Capturing Url Parameters in ReactJS using Typescript

This sounds like it’s a very easy thing to do. There are a lot of resources out there on the web, however, I certainly did not find it straight-forward.

My use case here was very simple: the site had failed to do something, I had the reason, and I just wanted to display that to the user (maybe at some stage I’ll move the response into the body, but I thought this would be an easy option for now.

How

The first step is to bring RouteComponentProps into your React file:

import { RouteComponentProps } from 'react-router';

Your component should have a class signature similar to this:

export class AddSiteFailure extends Component<IProps, IState> {

If you’re interested in some common Typescript syntax differences for React, I recently posted on this very subject.

In the above class definition, we’re accepting IProps and IState. IProps needs to be amended slightly:

interface IProps extends RouteComponentProps<IMatchParams> {    
}

interface IState {
}

So, we’re inheriting from the RouteComponentProps that we imported earlier, and we’re telling it that the structure of the parameters will be defined in an interface called IMatchParams. We’ll need to define that:

interface IMatchParams {
    reason: string
}

Okay, so far, we have a standard props structure, but we’re now inheriting from this new RouteComponentProps, and we’re telling it that the URL parameters will be defined in the interface IMatchParams. So, why does IMatchParams have a string property called “reason”?

The answer to that lies in your App.js / App.tsx. This is the file that manages the routing of your app. In the Render method, your file should have an entry similar to this:

<Route path='/addSiteFailure' component={AddSiteFailure} />

So, you need to tell it that you’ll be accepting a parameter, and you need to give that parameter a name; for example:

<Route path='/addSiteFailure/:reason' component={AddSiteFailure} />

Now, when you navigate to the page, the additional Url parameter will be internally referred to as “reason”, which is how it maps to IMatchParams.reason.

Moving to Typescript with React

Typescript gives you a number of nice little statically typed features, which Javascript is sadly lacking. However, looking online, most of the tutorials and references use Javascript. This is a handy little post to allow you (or me) to use Typescript; or to use Javascript, and then transition to Typescript. Since you can use both in your project, you might find that migrating files one at a time allow you to gradually transition your code-base.

File name

When you create your first React app, you get a, by now, pretty standard SPA app. The entire app is running Javascript. To change one of the files over to Typescript, simply change the extension:

You now have your first Typescript component… Now the errors begin!

Props

Parameter ‘props’ implicitly has an ‘any’ type, but a better type may be inferred from usage.ts(7044)

This warning appears when you have the following constructor:

constructor(props) {  

Now that you’ve moved from a dynamic to a statically* typed language, Typescript is simply suggesting that you may have a better type than the Any** type that is assigned by default.

The easiest, and best transition here is simply to tell Typescript the type; for example:

interface IProps {
}

export class Home extends Component<IProps> {

  constructor(props: IProps) {    

If you actually have any properties, then you’ll need to include them in your interface; for example:

interface IProps {
  myValue: boolean
}

State

In Javascript, you define state by usage in the constructor; for example:

export class FetchData extends Component {
  static displayName = FetchData.name;
  constructor(props) {
    super(props);
    this.state = { forecasts: [], loading: true };
  }

Again, you need to define what the structure of state is:

interface IState {
  forecasts: string[];
  loading: boolean;
}

Then, you can reference that in the constructor, and pass the type into the base component:

export class Home extends Component<IProps, IState> {

  constructor(props: IProps, ) {    
    super(props);
    this.state = { 
      forecasts: [], 
      loading: true 
    };
  }

External Interface Files

One of the consequences of declaring these interfaces, is that you’ll quickly find that you need to reference the same interface from more than one place. For example, you may read some data in one component, and then display it in another. You could simply redeclare the interface in both places, but that feels dirty.

To get around this, you can simply declare a set of interfaces in a single file, or set of files. In C#, I would declare a single interface per file, so I’m tempted to lean towards this approach:

This doesn’t necessarily apply to any interfaces that are relevant to only a single component (for example, the interface for the props – unless they are shared – feels like it’s perfectly happy in the same file as the component).

Raising Events

In the same way as you now have to define what props look like, when you raise an event, you need to define what the event looks like; that is, you must tell Typescript the event type that you’re handling.

interface SearchProps {
    searchText: string;
    searchAction: (e: React.MouseEvent<HTMLButtonElement>) => void;
}
function Search(props: SearchProps) {
    
    return (
        <div>
            <label>Search</label>
            <textarea>{props.searchText}</textarea>
            <button onClick={props.searchAction}>Search</button>
        </div>
    );
}
export default Search;

External Libraries

If you’re referencing an external library, you may not have the Typescript definitions; let’s take reactstrap for example:

Could not find a declaration file for module ‘reactstrap’. ‘c:/myproject/ClientApp/node_modules/reactstrap/dist/reactstrap.cjs.js’ implicitly has an ‘any’ type.

Try `npm install @types/reactstrap` if it exists or add a new declaration (.d.ts) file containing `declare module ‘reactstrap’;`ts(7016)

You should be able to simply install this – which, in fact, it tells you to do in the error message:

npm install @types/reactstrap

References

https://stackoverflow.com/questions/46987816/using-state-in-react-with-typescript/46987987

Notes

* I’m not convinced that Typescript qualifies as a true statically typed language, rather it provides static typing for a dynamically typed language.

** Any is Typescript’s way of allowing you to revert to JavaScript, and just not type a specific variable; this is why I have doubts as to whether Typescript can be considered statically typed.

Short Walks – Submit a single row of data in ReactJS

While looking into the react sample app, I came across a scenario whereby you might need to pass a specific piece of data across to an event handler. A lot of the online examples cover data state; but what happens when you have a situation such as the one in the sample app; consider this:

In this instance, you want to pass the temperature of the line you’ve selected. The solution is quite simple, and documented here:

private renderForecastsTable(forecasts: WeatherForecast[]) {
    return <table className='table'>
        <thead>
            <tr>
                <th>Date</th>
                <th>Temp. (C)</th>
                <th>Temp. (F)</th>
                <th>Summary</th>
            </tr>
        </thead>
        <tbody>
        {forecasts.map(forecast =>
            <tr key={ forecast.dateFormatted }>
                <td>{ forecast.dateFormatted }</td>
                <td>{ forecast.temperatureC }</td>
                <td>{ forecast.temperatureF }</td>
                <td>{forecast.summary}</td>
                <td><button onClick={(e) => this.handleClick(e, forecast)}>Log Temperature!</button></td>
            </tr>
        )}
        </tbody>
    </table>;
}

Here, we’re passing the entire forecast object to the handler; which looks like this:

handleClick = (event: React.FormEvent<HTMLButtonElement>, forecast: WeatherForecast) => {
    console.log("timestamp: " + event.timeStamp);
    console.log("data: " + forecast.temperatureC);
}

https://reactjs.org/docs/forms.html

https://reactjs.org/docs/handling-events.html

Adding a New Screen to the React Template Project

In this post I started looking into ReactJS. Following getting the sample project running, I decided that I’ve try adding a new screen. Since it didn’t go as smoothly as I expected, I’ve documented my adventures.

The target of this post is to create a new screen, using the sample project inside Visual Studio.

Step 1

Create a brand new project for React:

If you run this out of the box (if you can’t because of missing packages then see this article), you’ll get a screen that looks like this:

Step 2

Add a new tsx file to the components:

Here’s some code to add into this new file:

import * as React from 'react';
import { RouteComponentProps } from 'react-router';
 
 
export class NewScreen extends React.Component<RouteComponentProps<{}>, {}> {
    public render() {
        return <div>
            <h1>New Screen Test</h1>
        </div>;
    }
}
 

The Javascript as HTML above is one of the things that makes ReactJS an appealing framework. Combine that with Typescript, and you get a very XAML feel to the whole web application.

Step 3

Add a link to the Navigation Screen (NavMenu.tsx):

<div className='navbar-collapse collapse'>
    <ul className='nav navbar-nav'>
        <li>
            <NavLink to={ '/' } exact activeClassName='active'>
                <span className='glyphicon glyphicon-home'></span> Home
            </NavLink>
        </li>
        <li>
            <NavLink to={ '/counter' } activeClassName='active'>
                <span className='glyphicon glyphicon-education'></span> Counter
            </NavLink>
        </li>
        <li>
            <NavLink to={ '/fetchdata' } activeClassName='active'>
                <span className='glyphicon glyphicon-th-list'></span> Fetch data
            </NavLink>
        </li>
        <li>
            <NavLink to={'/newscreen'} activeClassName='active'>
                <span className='glyphicon glyphicon-th-list'></span> New screen
            </NavLink>
        </li>
 
    </ul>
</div>

If you run this now, you’ll see the navigation entry, but clicking on it will give you a blank screen. It is just that scenario that motivated this post!

Step 4

Finally, the routes.tsx file needs updating so that it knows which screen to load when:

import * as React from 'react';
import { Route } from 'react-router-dom';
import { Layout } from './components/Layout';
import { Home } from './components/Home';
import { FetchData } from './components/FetchData';
import { Counter } from './components/Counter';
import { NewScreen } from './components/NewScreen';
 
export const routes = <Layout>
    <Route exact path='/' component={ Home } />
    <Route path='/counter' component={ Counter } />
    <Route path='/fetchdata' component={FetchData} />
    <Route path='/newscreen' component={NewScreen} />
</Layout>;

Forcing an NPM Restore

I’ve recently started looking into the Javascript library ReactJS. Having read a couple of tutorials and watched the start of a Pluralsight video, I did the usual and started creating a sample application. The ReactJS template in VS is definitely a good place to start; however, the first issue that I came across was with NPM.

Upon creating a new web application, I was faced with the following errors:

The reason being that, unlike NuGet, npm doesn’t seem to sort your dependencies out automatically. After playing around with it for a while, this is my advice to my future self on how to deal with such issues.

The best way for force npm to restore your packages seems to be to call

npm install

either from Powershell, or from the Package Manager Console inside VS.

Powershell

On running this, I found that, despite getting the error shown above, the packages were still restored; however, you can trash that file:

Following that, delete the node_modules directory and re-run, and there are no errors:

Package Manager Console

In Package Manager Console, ensure that you’re in the right directory (you’ll be in the solution directory by default, which is the wrong directory):

References

https://stackoverflow.com/questions/12866494/how-do-you-reinstall-an-apps-dependencies-using-npm

Bing Maps – Finding an Address from Longitude / Latitude

Oddly, finding an address from given coordinates is not as straightforward as it first appears. The key seems to be to use the SearchManager.

SearchManager

The following is a typescript implementation that will populate an input element called myLocationText:

function GetMap(position): void {    
    map = new Microsoft.Maps.Map(
        document.getElementById('map'),
        { credentials: "MyKey" });

    Microsoft.Maps.loadModule('Microsoft.Maps.Search', function () {
        var searchManager = new Microsoft.Maps.Search.SearchManager(map);
        var location = new Microsoft.Maps.Location(position.latitude, position.longitude);
    
        var mapOptions = {        
            center: location,        
            mapTypeId: Microsoft.Maps.MapTypeId.aerial,
            zoom: 10,        
            showScalebar: false        
        }    

        var reverseGeocodeRequestOptions = {
            location: location,
            callback: function (answer, userData) {
                map.setView(mapOptions);
                var myLocation = <HTMLInputElement>document.getElementById('myLocationText');                
                myLocation.value = answer.address.formattedAddress;
            }
        }
        searchManager.reverseGeocode(reverseGeocodeRequestOptions);
    });

If you want to get it to show your current location, then try this:

function findMe(position) : void {
   
    var latlong = new Microsoft.Maps.Location(position.coords.latitude,
        position.coords.longitude);

    GetMap(latlong);
    
}

Shows the correct address

References

http://www.bing.com/api/maps/sdkrelease/mapcontrol/isdk#searchByPoint+JS

http://bingmapsv8samples.azurewebsites.net/#Calculate%20Distance%20From%20Route

https://www.nuget.org/packages/Microsoft.BingMaps.V8.TypeScript/

TypeScript

Javascript is a dynamic, interpreted language. What that means is that, if you mis-type or mis-spell a variable, or even if you don’t bother to declare it, you won’t get notified at compile time (because, for a start, there is no compile time).

One possible way around this is to use one of the languages that compile down to Javascript. That does seem like a bizarre notion – that you should compile down to a second language; but it does mean (as the name suggests) that you can introduce some static typing into your Javascript.

The following was with VS2017, but you can use VS2015. I believe earlier versions don’t support Typescript out of the box (but I could be wrong).

Javascript

The first thing we’ll do is create a new web project and create some Javascript:

Create new project

Create new project

Create a basic html page:

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <title></title>
    
</head>
<body>
    <div>
        <input id="testInput" type="text" />
    </div>
    <div>
        <p id="testOutput">Output</p> 
    </div>
    <div>
        <button onclick="buttonClicked()">Test</button>
    </div>

    <script src="typescript.js"></script>

    
</body>

And the Javascript:

function buttonClicked() {
    var input = getElementById("testInput");
    var ouput = getElementById("testOutput");

    output.value = input.value;

}

This code will run (the web-site will appear), but it will not do what it’s supposed to.

Typescript

Now we have a project, the next thing to do is to add .ts file to project. This gets compiled into a .js file, and can be referenced with a .js extension. Just copy the code:

Code sample

As you can see, the code no-longer “compiles”. The correct Typescript looks more like this:

function buttonClicked() {
    var input = <HTMLInputElement>document.getElementById("testInput");
    var output = document.getElementById("testOutput");

    output.innerText = input.value;

}

The <> brackets are typescript casts. Once you build this typescript file, it will compile down to Javascript:

Project tree

The compiled Javascript now looks like this:

function buttonClicked() {
    var input = document.getElementById("testInput");
    var output = document.getElementById("testOutput");
    output.innerText = input.value;
}
//# sourceMappingURL=typescript.js.map

The typescript.js.map file tells it where your file really is and, from looking at the debugger, we can see that the typescript file is being used:

All works well:

But why

As you can see, above; we had a piece of Javascript code that didn’t work, but it ran. Any statically typed language would have simply failed to compile. Typescript means that you can benefit from this additional check before runtime. There is a cost here, and that is that you lose the dynamic typed capability of Javascript; for example, the following won’t compile:

IMHO, this is a good thing, but I’m aware there are people out there in the world that think otherwise.

References

http://stackoverflow.com/questions/34888434/how-to-reference-a-typescript-file-from-a-web-page

http://stackoverflow.com/questions/12686927/typescript-casting-htmlelement