ASP.NET Core Basics: React with an API
In the past, I have done some exploration on Aurelia and Angular via the ASP.NET Core Basics series. This post is going to take a similar approach as I start doing some exploration with React. The code for the project will be in the same repo as the previous basics examples and will be utilizing the same API to pull data. The code before adding the React project can be found here.
This post is going to cover adding a React project to the existing using the React template that is now built into Visual Studio. The same thing can be accomplished using the .NET CLI so don’t feel like Visual Studio is required. The goal for the React project in this initial post will be to connect to the contacts API and download a list of contacts and render that to the screen. In future posts, I hope to expand this functionality to match that of the Aurelia and Angular projects.
Project Creation
Right-click and select Add > New Project.
In the Add New Project dialog select the ASP.NET Core Web Application. In the case of the sample, the project will be named React. Click OK to continue.
On the next screen make sure and select ASP.NET Core 2.0 and the React.js template. Then click OK.
The following is the resulting React project in the context of the full solution.
Next, make sure and run npm install from a command prompt in the React project’s directory to ensure all the npm packages get restored.
Adding the Contact List
Inside the ClientApp/components/ directory add a file name ContactList.tsx. TSX is the TypeScript version of the React JSX file type. The official docs on JSX can be found here. Since this is my first time working with React I took the FetchData.tsx file and copied the contents and used that as the starting point for my contact list. To lead with there is an interface for what should define a contact.
interface Contact { id: number; name: string; address: string; city: string; state: string; postalCode: string; phone: string; email: string; }
Next, we have an interface for the state of this component with contains a loading flag and an array of contacts.
interface ContactListState { contacts: Contact[]; loading: boolean; }
In the constructor for the component is where the data is pulled from the API using fetch. The data from the API is then saved to the state of the component using the setState function.
constructor() { super(); this.state = { contacts: [], loading: true }; fetch('http://localhost:13322/api/contactsApi/') .then(response => response.json() as Promise<Contact[]>) .then(data => { this.setState({ contacts: data, loading: false }); }); }
Next, the component has a function named renderContactsTable which takes an array of contacts and returns how they should be rendered. In this case, the contacts are rendered to a table that displays the contact ID and Name.
private static renderContactsTable(contacts: Contact[]) { return <table className='table'> <thead> <tr> <th>ID</th> <th>Name</th> </tr> </thead> <tbody> {contacts.map(contact => <tr key={contact.id}> <td>{contact.id}</td> <td>{contact.name}</td> </tr> )} </tbody> </table>; }
Finally, there is the render function. As you can guess this is what gets called to render the component. In this case, either “Loading” or the contact list gets displayed depending on if the contact list data has been loaded or not.
public render() { let contents = this.state.loading ? <p><em>Loading...</em></p> : ContactList.renderContactsTable(this.state.contacts); return <div> <h1>Contact List</h1> {contents} </div>; }
The following is the full file for reference.
import * as React from 'react'; import { RouteComponentProps } from 'react-router'; import 'isomorphic-fetch'; interface ContactListState { contacts: Contact[]; loading: boolean; } export class ContactList extends React.Component<RouteComponentProps<{}>, ContactListState> { constructor() { super(); this.state = { contacts: [], loading: true }; fetch('http://localhost:13322/api/contactsApi/') .then(response => response.json() as Promise<Contact[]>) .then(data => { this.setState({ contacts: data, loading: false }); }); } public render() { let contents = this.state.loading ? <p><em>Loading...</em></p> : ContactList.renderContactsTable(this.state.contacts); return <div> <h1>Contact List</h1> {contents} </div>; } private static renderContactsTable(contacts: Contact[]) { return <table className='table'> <thead> <tr> <th>ID</th> <th>Name</th> </tr> </thead> <tbody> {contacts.map(contact => <tr key={contact.id}> <td>{contact.id}</td> <td>{contact.name}</td> </tr> )} </tbody> </table>; } } interface Contact { id: number; name: string; address: string; city: string; state: string; postalCode: string; phone: string; email: string; }
Add Contact List to Navigation
Now that we have the contact list component it needs to be added to the navigation menu. The first step is to add it to the application’s router. This can be found in the routes.tsx file. The file is short so I am going to include the full content. Lines 7 and 13 are the ones added to handle our contact list.
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 { ContactList } from './components/ContactList'; export const routes = <Layout> <Route exact path='/' component={Home} /> <Route path='/counter' component={Counter} /> <Route path='/fetchdata' component={FetchData} /> <Route path='/contactlist' component={ContactList} /> </Layout>;
The last change is to add a navigation link to the NavMenu found in the NavMenu.tsx file. As I am sure most of us are used to adding an item to the nav menu is just adding a new li, but with the React specific NavLink bit.
<li> <NavLink to={'/contactlist'} activeClassName='active'> <span className='glyphicon glyphicon-th-list-alt'></span> Contact List </NavLink> </li>
Wrapping Up
React is different than both Aurelia and Angular. Don’t take that as a good or bad thing. I don’t plan to pick on a side on the Angular vs React debate I just want to get a good feel for the different frameworks. So far the React experience has been pretty nice and I look forward to doing more exploration.
You can find the finished code for this post here.
ASP.NET Core Basics: React with an API Read More »