DEV Community

Cover image for Learning React - Exercise control over your component state with Typescript
Jon Hilton
Jon Hilton

Posted on • Updated on • Originally published at jonhilton.net

Learning React - Exercise control over your component state with Typescript

The last post left us with a bit of a problem.

Although our user component retrieves and displays data from ASP.NET API, it also flashes up some hard-coded data before the real data shows up.

It seems like we could just remove the hard-coded data so let's try that...

    public state = {
        "users": []
    };
Enter fullscreen mode Exit fullscreen mode

Seems reasonable, except for one problem, it doesn't compile.

Yes that's right, javascript gets compiled these days! And in this case we run into an error.

This seems odd at first, it was working before.

Turns out, when we had our hard-coded data, Typescript was able to infer the type from the structure of this data.

public state = {
    "users": [
        { "id": 1, "name": "Jon Hilton", "summary": "36 / Lead Developer" },
        { "id": 2, "name": "Janine Smith", "summary": "32 /  Senior Engineer" }
    ]
};
Enter fullscreen mode Exit fullscreen mode

So, because that data included an id property, everything "just worked".

Now we don't have any data, there's nothing for the compiler to go off, so it blows up when it comes to this line...

{this.state.users.map(user => <UserRow key={user.id} user={user} />)}
Enter fullscreen mode Exit fullscreen mode

Turns out, this isn't a problem if we stop being lazy and actually define types for our state.

export interface IState {
    users: IUser[];
}

export interface IUser {
    id: number,
    name: string,
    summary: string
}
Enter fullscreen mode Exit fullscreen mode

Then we can declare our component state's type...

export default class MyUsers extends React.Component<any, IState>{
Enter fullscreen mode Exit fullscreen mode

And finally, tweak the code where we set the initial state (to indicate the type).

public state: IState = {
    "users": []
};
Enter fullscreen mode Exit fullscreen mode

Now everything compiles, plus we have the benefit that we've removed the ambiguity about our state.

You'll get proper intellisense in Visual Studio Code and there's less uncertainty all round!

Just before we continue, if you fancy a gander at the source code for this series grab it here :-)

Loading...

This has removed our flash of data, but what if we want to show a loading indicator when the data's being retrieved?

We need a way to render different content if we're loading data, then show the list once the data's available.

As with all things in React, if we can change the underlying state as we're making the API call, the user interface can react to that and show a loading indicator of some kind.

We can add a loading boolean to IState.

export interface IState {
    loading: boolean;
    users: IUser[];
}
Enter fullscreen mode Exit fullscreen mode

Set it to false for starters.

public state: IState = {
    loading: false,
    "users": []        
};
Enter fullscreen mode Exit fullscreen mode

Then flip this flag when we're loading data from the back-end.

public async componentDidMount() {
    this.setState({ loading: true }); // toggle on
    const result = await fetch('https://localhost:44348/api/user');
    const users = await result.json();
    this.setState({ users, loading: false }); // toggle off
}
Enter fullscreen mode Exit fullscreen mode

And finally make our html react to this and render some kind of loading indicator (when state.loading is true).

<h1>My Users</h1>
{this.state.loading && <div>Loading...</div>} // add this
<table className="user-list">
    <tbody>
        {this.state.users.map(user => <UserRow key={user.id} user={user} />)}
    </tbody>
</table>
Enter fullscreen mode Exit fullscreen mode

This looks a bit weird the first time you see it so let's break it down.

{this.state.loading && <div>Loading...</div>}
Enter fullscreen mode Exit fullscreen mode

This will show the Loading div if this.state.loading evaluates to true.

As a C# developer you'll be used to the more classic if statement.

So what is this && madness?!

Turns out, in javascript, the && logical operator returns the value of one of the specified operands.

If you have an expression like this.

const isSunday = true;
const result = isSunday && 'It\'s Sunday';
Enter fullscreen mode Exit fullscreen mode

The result would be 'It's Sunday'.

const isSunday = false;
const result = isSunday && 'It\'s Sunday';
Enter fullscreen mode Exit fullscreen mode

And this would return false!

The table over here explains this much better than I'd hope to!

Javascript Logical Operators

So in the end, this is just a concise way of saying "show the loading indicator if this.state.loading is true".

Your state is typed!

Whilst it's tempting to throw any around all over the place to avoid declaring types, this shortcut ultimately makes some things more difficult and removes the benefits of using Typescript in the first place.

Create your types, use conditional rendering and your components will react in a predictable way, based purely on the underlying state of the component.

Remember, if you fancy a gander at the source code for this series, you can grab it here :-)

photo credit: Pranav Bhatt Sign, Southern Africa via photopin (license)

Discussion (1)

Collapse
vshyrokov profile image
Viktor Shyrokov

As for me it's much easier and faster to work with typescript. You could avoid a types errors, because you would have to pass only exact props as needed.