JSFiddle - React, Tailwind, and code Playground

HTML

<script src="https://code.jquery.com/jquery-2.2.4.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.0/knockout-min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.8.3/underscore-min.js"></script>
<script src="https://rawgit.com/kamranayub/65399fa247a6c182bc65/raw/b5d83a75b60b42019277ab0b738d474bef3e628a/ko.bindingReport.js"></script>
<h3>
Introduction
</h3>
<p>
This widget is running faster in this demo (outside my application), but still slowly.
</p>
<p>
I want to make it faster. To see the problem, uncheck and re-check "Show meal dates" below, or re-run the demo.
</p>
<p>
In my app the list of users is this size, and is filterable, so I need to re-render when items become visible.
</p>
<h3>
Demo
</h3>

<input type="checkbox" data-bind="checked:showMeals" value="1"> Show meal dates<br>


<table>
  <tbody data-bind="foreach: guests">
    <tr>
      <td data-bind="text: firstname"></td>
      <td data-bind="text: lastname">Data</td>
      <td>
        <meals params="guest: $data, show: $root.showMeals"></meals>
      </td>
    </tr>
  </tbody>
</table>

    <template id='meals-template'>
        <!-- ko if: show -->
        <div data-bind="click: function(){}, clickBubble: false">
        <!-- Once the page has loaded, the meals array never changes -->
        <!-- ko foreach: meals -->
        <div class="dates">
            <span class="dates__label" data-bind="text: name"></span>
            <span data-bind="html: $root.createHtml($data)"></span>
            <!-- commented ko foreach: dates
            <span class="dates__date" data-bind="css: {
                is_setup: is_setup,
                is_needed: $component.guest.meals().hasOwnProperty(id),
                is_assigned: $component.guest.meals().hasOwnProperty(id) && $component.guest.meals()[id].diningRoom != null,
                is_selected: $component.guest.meals().hasOwnProperty(id) ? $component.guest.meals()[id].selected : false
  ...

CSS

.rowSelected td { color: black; background: yellow; }
    .dates {
        font-size: 10px;
    }
    .dates__label {
        width: 50px;
        display: inline-block;
    }
    .dates__date {
        font-size: 10px;
        display: inline-block;
        padding: 1px;
        text-align: center;
        width: 16px;
        color: #ccc;
        margin: 0 0 2px;
    }
    .is_setup {
        background-color: #f6f6f6;
    }
    .is_needed {
        background-color: orange;
        color: #666;
        cursor: pointer;
    }
    .is_assigned {
        background-color: greenyellow;
        color: #666;
    }
    .is_selected {
        background: deeppink;
    }

JavaScript

function MealsViewModel(params) {
  // 'params' is an object whose key/value pairs are the parameters
  // passed from the component binding or custom element.
  this.meals = params.meals || meals;
  this.guest = params.guest;
  this.show = params.show;
  


  // Process these params into the data structure we need to render
}
ko.components.register('meals', {
  viewModel: MealsViewModel,
  template: { element: 'meals-template' }
});

viewModel = function(guests) {
  var self = this;
  self.showMeals = ko.observable(true);
  self.guests = ko.observableArray(guests);
  
  self.toggleMealDateSelected = function(data) {
    data.selected(!data.selected());
  };
   self.createHtml = function(meal){
     var parts = [];
    for (var i = 0; i < meal.dates.length; i++) {
       
       parts.push("<span");
       parts.push("class=\"");
       if(meal.dates[i].is_setup ) parts.push("is_setup,");
       if(meal.dates[i].is_needed ) parts.push("is_needed,");
       if(meal.dates[i].is_assigned ) parts.push("is_assigned,");
       if(meal.dates[i].is_selected ) parts.push("is_selected,");
       parts.push("\"");
       
       parts.push("data-diningroom-id=\"");
       parts.push("123");
       parts.push("\">");
       parts.push(new Date(meal.dates[i].date).getDate());
       
       parts.push("</span>");
       
    }
    return parts.join(" ");         
  }
};

/////////////////////////////////////////////////////////
// Data below. Initialization at bottom
/////////////////////////////////////////////////////////
var guest = {
  "id": 2235,
  "firstname": "John",
  "lastname": "Doe",
  "catered": true,
  "dietaryRequirements": false,
  "meals": {
    "333": {
      "date": "2016-09-06",
      "name": "Breakfast",
      "diningRoom": null,
      "id": 55,
      "selected": false
    },
    "334": {
      "date": "2016-09-07",
      "name": "Breakfast",
      "diningRoom": null,
      "id": 56,
      "selected": false
    },
    "335": {
      "date": "2016-09-08",
 ...