Introduction
In this part of our tutorial, we'll be building our high performance ASP.NET Core React.js components without using Redux or JQuery. If you haven't completed Part 1 of this tutuorial, you'll want to do that first and then return to this page. We'll start by creating our client-side models.
Client-side Models
Client-side what? Since our React components will need access to our models, we will need client side models as well as the server-side models we created earlier. Fortunately, our client-side models will be much simpler since TypeScript has just a few simple types and we will not need any attributes. Just like our server-side models, we will have three classes: Actor
, Movie
, and MovieActor
.
Start by expanding the ClientApp folder, then right-click on the ClientApp folder, select Add, then New Item...(figure 1). From the Templates box on the left, select ASP.NET Core, then Web, then Scripts. Select TypeScript File from the middle box, and enter the name models.ts (figure 1).
Figure 1
Copy and paste the three models shown below (figure 2):
export class Actor{
Id: number;
Name: string;
Gender: string;
Age: number;
Picture: string;
}
export class Movie{
Id: number;
Title: string;
Director: string;
DateReleased: string;
ReleasedBy: string;
Rating: string;
Genre: string;
GrossRevenue: number;
}
export class MovieActor{
MovieId: number;
ActorId: number;
}
Figure 2
The Actor Component
Now let's create the Actor React.js component. As I mentioned in Part 1, each of our components will live in their own folder. So start by creating a folder under ClientApp/Components called Actor
. Then right-click the Actor folder, select Add, then New Item... From the left-side of the Add New Item dialog box, select ASP.NET Core, then Web, then Scripts (fig 3). Then select TypeScript JSX file from the middle box and name the file: Index.tsx.
Figure 3
TypeScript JSX files are what we use to create React components.
Imports
Import statements in ES6 (the current version of JavaScript) are similar to using
statements in C# - they allow us to reference other script modules. We'll need to reference our client-side models and a few other things so let's add some import
statements. Our first three import
s include: a reference to React, a reference to React Router, and a reference to our client models. Copy these three import
statements as shown below (fig 4).
import * as React from 'react';
import { RouteComponentProps } from 'react-router';
import * as models from '../../models'
Figure 4
React components are stateful and are called 'controlled'. In React, you only ever modify the state and React takes care of the rendering. We don't ever touch the DOM, which is why we don't need JQuery. In fact, manipulating the DOM is potentially problematic since you can corrupt your component's state. It's a very clean architecture but if you're a seasoned developer, you have to fight the urge to manipulate the DOM directly. We will use an Interface to define the state for the Actor
component. Just below the import
statements you just copied, copy the following interface (figure 5).
interface ActorState {
actor: models.Actor[]
loading: boolean
}
Figure 5
Let's continue. Our component will be usable anywhere in our application (and reusable by other applications), so the class declaration must start with 'export
' and will also extend Rect.Component
. We'll start with the constructor, which will initialize the state of the component and fetch the data for the view. Copy the code shown below (figure 6):
export class Actors extends React.Component<routecomponentprops<{}>, ActorState> {
constructor(props) {
super(props);
this.state = {
actor: [],
loading: true
};
fetch('api/actor/index')
.then(response => response.json() as Promise<models.actor[]>)
.then(data => {
this.setState({
actor: data,
loading: false,
});
});
}
Figure 6
The magic of React components happens in the render()
method. Whenever you change the state of your component by setting one of the values, React will re-render your component. So let's write our render
method as shown below (fig 7). You may have noticed that we've inserted the variable: {contents} in the returned markup. This simply allows us to breakup the markup into more manageable pieces, which will become more important as our components get more complicated.
Figure 7
Lastly, we just need to write our renderTable()
method. It's a fairly basic HTML table, but you'll want to take note of a couple of things. The JavaScript .map()
method is used to iterate our data, which is passed to our method as the parameter: actor
. Also React highly recommends adding a unique 'key
' to markup that takes the form of tables or ul
and ol
that can potentially contain many entries. This allows React to optimize how it re-renders your component, i.e., in our example, re-rendering only the rows that have changed. Go ahead and type the markup shown below (figure 8).
Figure 8
That completes our component. Next, we'll move on to our controller.
The Controller
As I mentioned in Part 1, our controller will be an ASP.NET Core WebAPI controller. It will return JSON, which means we can leverage it to also serve native mobile applications. Let's get started.
Right-click on the Controllers folder and select Add, then Controller. If a popup entitled 'Add dependencies to enable scaffolding' appears, select Minimal Dependencies and wait for Visual Studio to install some scaffolding packages, then try again. From the Add Scaffold popup, select API Controller with Actions using Entityframework. Then from the next popup, select Actor
for the Model
, and AppDbContext
for the Data context (figure 9). Note if your project contains any compiler errors, the operation will fail and you will need to address those first.
Figure 9
We're going to make a small change to the controller. We're going to rename the GetActors()
method to Index()
for the sake of keeping with old MVC conventions (indulge me on this one). Also, we're adding the [HttpGet("[action]")]
attribute to allow us to call the method using the action name (Index
). Go ahead and make those two changes now (figure 9.1).
[Produces("application/json")]
[Route("api/Actors")]
public class ActorController : Controller
{
private readonly AppDbContext _context;
public ActorsController(AppDbContext context)
{
_context = context;
}
[HttpGet("[action]")]
public IEnumrable<Actor> Index()
{
return _context.Actors;
}
Figure 9.1
Routing
Routing in our React Single Page Application is handled by the react-router component. We need to tell it about our new component by adding entries to the ClientApp/routes.tsx and ClientApp/components/navmenu.tsx files. Make the modifications shown below (figures 10 and 11).
Figure 10
Figure 11
At this point, we can run our application and access our Actor
component (aka view). You won't have any data in your view, but if you'd like to see data at this juncture, you can simply add it to the database using SQL Management Studio.
Figure 12
That concludes Part 2 of this tutorial. Stay with us. In Part 3, we'll be making the magic happen by adding our Create
, Edit
, Details
and Delete
methods!
How to Implement CRUD forms with React and ASP.NET Core - Part 1
History
- 11/8/2017: Initial article