MVC vs React

Les Pinter

Introduction | MVC with Razor | React | The big difference | Conclusion

Introduction

Gone are the days when articles on web development could start out by saying "There are two ways to build web pages". There are dozens, if not hundreds.

However, many of us have ended up as painted ladies serving Microsoft, so we use Model-View-Controller (MVC) and the Razor engine. But increasingly, Single-Page Applications (SPAs) built using Angular, React or Vue are gaining in popularity.

I finally got around to building a little web page app that lists a table of Customers. Here's the table structure and the data in my table:

Listing 1 - the Customer table

  USE [Test]
  GO
  
  CREATE TABLE Customer (
    [ID] [int] IDENTITY(1,1) NOT NULL PRIMARY KEY,
    [FirstName] [varchar](30),
    [LastName] [varchar](30),
    [Address] [varchar](40),
    [City] [varchar](20),
    [State] [char](2),
    [ZIP] [varchar](10) )
  
    ID   FirstName    LastName       Address               City                 State ZIP
    ---  ------------ -------------- --------------------- -------------------- ----- -------
    1    Les          Pinter         35056 Highway 190     Springville          CA    93265
    2    Ying-Ying    Chang-Pinter   35056 Highway 190     Springville          CA    93265
    3    Francisco    Arce           Yarto 37              Mexico City          DF    01060
  

Create a new MVC ASP.NET application. Right-click on the project name in the Solution Explorer and select Add, New, ADO model. Select your customer table in the ensuing dialog. It will create an .edmx file and generate a model derived from the dbContext class with a name ending in Entities. Mine came from a database called Test, so my model's name is TestEntities. dbContext classes retrieve data from your database (and can save changes to it, for that matter.)

All I want to do for this simple comparison is to produce a web page that lists the data in the Customer table. Simple enough, ┬┐no?

So what's the difference in the coding that's required, and if one is harder than the other, is is worth the additional effort?

MVC with Razor

There are plenty of Writing your first MVC application web pages out there. The one that I like to refer people to is https://www.codeproject.com/Articles/866143/Learn-MVC-Project-in-days-Day. You might also like https://docs.microsoft.com/en-us/aspnet/mvc/overview/getting-started/introduction/getting-started

The MVC approach creates a Controller and a View. Here's the essence of the controller code:

Listing 2a - the Controller class

using System.Net;
using System.Data;
using System.Linq;
using System.Web.Mvc;
using System.Data.Entity;

namespace MVC.Controllers
{
  public class CustomersController : Controller
  {
    private TestEntities db = new TestEntities();
      // GET: Customers
      public ActionResult Index()
      {
        return View ( db.Customers.OrderBy(x=>x.LastName).ToList() ) ;  // (This is like a SQL Select statement in Entity-Framework)
      }
  }
}

Actually, the generated code also includes methods to add, edit, display and delete a single row in the table. Click to see the code.

Notice that almost all of the code is devoted to Add, Edit and Delete operations. Thanks to Entity-Framework, these are all trivial. Add a row, call db.SaveChanges(); make a change, call db.SaveChanges(); delete a row, call db.SaveChanges().

There are five Views in the MVC "scaffolding" - Add, Edit, Details, Delete and Index. The @model keyword at the top of the View code is the parameter passed to the view from the controller. The model is the result of the SELECT statement executed by the Index ActionResult. (Note: MVC is the name of my project.) The IEnumerable in the view's model declaration means that a list of Customer objects is being passed; all of the other views define a single Customer object at the top of the view.

The Index view lists the contents of the Customer table:

Listing 3 - the Index View

@model IEnumerable<MVC.Customer>

@{
    ViewBag.Title = "Index";
}

<h2>Index</h2>

<p>
    @Html.ActionLink("Create New", "Create")
</p>
<table class="table">
    <tr>
        <th>
            @Html.DisplayNameFor(model => model.FirstName)
        </th>
        <th>
            @Html.DisplayNameFor(model => model.LastName)
        </th>
        <th>
            @Html.DisplayNameFor(model => model.Address)
        </th>
        <th>
            @Html.DisplayNameFor(model => model.City)
        </th>
        <th>
            @Html.DisplayNameFor(model => model.State)
        </th>
        <th>
            @Html.DisplayNameFor(model => model.ZIP)
        </th>
        <th></th>
    </tr>

@foreach (var item in Model) {
    <tr>
        <td>
            @Html.DisplayFor(modelItem => item.FirstName)
        </td>
        <td>
            @Html.DisplayFor(modelItem => item.LastName)
        </td>
        <td>
            @Html.DisplayFor(modelItem => item.Address)
        </td>
        <td>
            @Html.DisplayFor(modelItem => item.City)
        </td>
        <td>
            @Html.DisplayFor(modelItem => item.State)
        </td>
        <td>
            @Html.DisplayFor(modelItem => item.ZIP)
        </td>
        <td>
            @Html.ActionLink("Edit", "Edit", new { id=item.ID }) |
            @Html.ActionLink("Details", "Details", new { id=item.ID }) |
            @Html.ActionLink("Delete", "Delete", new { id=item.ID })
        </td>
    </tr>
}

</table>
    

(Note that I added the following line after the Home, About, Contact menu items in Views/Shared/_Layour.cshtml)


  <li>@Html.ActionLink("Customers", "", "Customers")</li>

Press F5 to launch the website and then click on the Customers link, and you'll see this:

Table produced by MVC controller and view

React

The React version of the same web page looks about the same, minus the Add/Edit/Delete/Details buttons

Table produced by React controller and view

Notice that the React version doesn't have Add/Edit/Delete buttons. My purpose here is to highlight the difference between MVC and React web server pages, so although I left in the functionality generated automatically for free by MVC, that's not the point of this article. Baby steps...

The controller is a little different from what we used in MVC/C#:

Listing 4 - Controller code for the React version of the website

using System.Linq;
using System.Web.Mvc;

namespace MVC_React.Controllers
{
  public class HomeController : Controller
  {
    public ActionResult Index()
    {
      return View();
    }

    public JsonResult getCustData()
    {
      using (TestEntities dc = new TestEntities())
      {
        var data = dc.Customers.OrderBy(a => a.LastName).ToList();
        return new JsonResult { Data = data, JsonRequestBehavior = JsonRequestBehavior.AllowGet };
      }
    }
  }
}

The getCustData() method returns data formatted as JSON (JavaScript Object Notation), which is (evidently) what JavaScript likes.

But the View is where this method is called - way down at the end (lines 75 - 76); the rendering of the CustGridTable component triggers the componentDidMount event handler at line 44, which calls the AJAX get method, like this:


  44.   $.get(this.props.dataUrl, function(data)...

which goes to the specified URL and puts the data into data, which passes it to items when it returns...)

Listing 5 - the React View

@{
  ViewBag.Title = "Index";
}

<h2>Customer list from a database using React JS</h2>

<div id="griddata" class="">

</div>

<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css" rel="stylesheet" />
<script src="https://code.jquery.com/jquery-2.2.0.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/0.14.6/react.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/0.14.6/react-dom.js"></script>

@* JSX parser library *@
<script src="https://cdnjs.cloudflare.com/ajax/libs/babel-core/5.8.23/browser.min.js"></script>

<script type="text/babel">

@* 2 react components: 1 for rows, and another for the table *@
    var CustGridRow = React.createClass({
      render : function(){
        return (
          <tr>
            <td>{this.props.item.FirstName}</td>
            <td>{this.props.item.LastName}</td>
            <td>{this.props.item.Address}</td>
            <td>{this.props.item.City}</td>
            <td>{this.props.item.State}</td>
          </tr>
        );
      }
    });

    var CustGridTable = React.createClass({
      getInitialState: function(){
        return {
        items:[]
        }
      },
      componentDidMount:function(){
        @* Fetch data via ajax *@
          $.get(this.props.dataUrl, function(data){
          if(this.isMounted()){
            this.setState({
            items: data
          });
        }
      }.bind(this));
    },
    render : function(){
      var rows = [];
      this.state.items.forEach(function(item){
        rows.push(
          <CustGridRow key={item.CustomerID} item={item} />);
        });
      return (
      <table className="table table-bordered table-responsive">
        <thead>
          <tr>
            <th>First Name</th>
            <th>Last Name</th>
            <th>Address</th>
            <th>City</th>
            <th>State</th>
          </tr>
        </thead>
        <tbody>
          {rows}
        </tbody>
      </table>);
    }
    });
    ReactDOM.render(
      <CustGridTable dataUrl="/home/getCustData" />,  document.getElementById('griddata')
    );
</script>

The two React components that are created in the code are CustGridRow and CustGridTable. The foreach...push at lines 54 - 55 create the <tr>items rows</tr>. The DataURL parameter tells the component where to get the rendered table, and the second parameter tells it to find the element with the id griddata and put the generated HTML there.

The Big Difference

The big difference is easy to miss: It's where the code is executed. The MVC code runs entirely on the server. It's not so much code if there are only three rows in the table, but what if there are three thousand?

The React code runs almost entirely in the user's browser - everything except the request for the JSON data. So rendering a large page takes less processing - potentially much less processing - when you use React.

However, there is another difference that might have escaped you, and it's this: The MVC code was written almost entirely by the Integrated Development Environment (IDE), Visual Studio. You have to write the React code, using JSX (that's what Babel is for), yourself.

Conclusion

If you use MVC, you run the risk of using many times more resources when rendering pages with large numbers of rows in tables. If you use React, the rendering is done by your users' browsers. So with MVC, the load on the server can be much, much heavier.

So what?

Facebook uses React because they have tens of thousands of hits per minute - may even per second. Unburdening the server is a BFD for Facebook. And Zuckerberg is loaded. So it doesn't matter how much it costs to write the JavaScript code to do most of the work in users' browsers. But it does matter to my customers.

Oh, they might say that they want scalability. But when they find out that it costs more, they want it less. And when the page volume is around 1 hit per second, if not 1 hit per minute, that fact combined with the cost generally persuades them that MVC is not such a bad deal after all.

If you have a rich client who wants a Rolls-Royce, by all means give them React. But if they want it "soon, good and cheap", with MVC and Razor you can usually give them all three.

❑❑❑