Stay with me on this, I promise it’s not too out there.

Learning React has been one of the ultimate exercises in my maxim “There is Nothing Old Under The Sun”, which is meant to remind ourselves that every idea, in some way, has come before. Yet each repetition is always in some way new and has a different spirit to it.

In knitting, some techniques exist to add texture and structure to a garment while wasting a minimum amount of resources (yarn, which has historically been in somewhat limited supply). Bodies have organic shape to them, bodies are not just cuboid or columnar. Bellies have curve, chests have dimension, arms and wrists change width, bottoms and legs as well.

With woven fabric, in order to make a fitted garment that has the correct range of motion and drape to the body, one has to cut a shape and remove triangles to traverse a steep curve (how one makes a dart) or a wider arc to traverse a gentler slope (such as the arc to make the seat of trousers, or the yoke of a shirt).

Knitted fabric does not solve this problem the same way. Since knitted garments generate fabric that does not need to be cut, and can generate shapes other than parallelagrams, knitted garments tend to solve this problem by repeating instructions in particular ways to generate more and less fabric in certain areas to create a shaped piece of fabric. Some patterns don’t need to be sewn at all, and a complex garment is generated from end to end by growing and shrinking the number of stitches generating fabric as needed.

Websites have a similar problem, actually. Dynamic features are desirable on websites, since they provide functionality that users want. But users don’t want to wait an excessive period of time for websites to load, or to manually refresh a page to see the results of their actions and any new content that has been posted since they arrived at the page. Sending too many resources is wasteful, and writing the same resources over and over in slightly different ways is also wasteful. This is where React comes in.

Before we dive deeply into my comparison, I’d like to introduce you to some custom terminology I have that this comparison relies on. Knitting has “live stitches” which are held open on needles and worked usually one at a time from the working yarn connected to the ball. I am going to call this worked stitch the “insertion point” while it is being worked, because computers also have an insertion point. From the blinking “cursor” in a text editor to the part of a web page that React can append to, computing relies on insertion points to insert new data and content at precisely the desired location. Knitters do not call the worked stitch an insertion point, but I feel it is important to draw this comparison so that we are ready to move into visualizing textile patterns as React concepts.

Short Rows Are Like Repeated Components

React breaks parts of a website into components which are like toy blocks that can be stacked together to make a larger whole. Unlike toy blocks, if we wanted all the red blocks to behave differently, we would simply change the “red blocks” component and all the red blocks in use would change to suit. This is different from CSS classes because this type of logic can be used to change behavior as well as styling.

React allows components to control other components. This is because a component can take parameters, called props or properties, and act on these parameters much as any method may act on its parameters. A component may be passed as a parameter much like any method may itself be passed as a parameter to another method to be called later.

A good reason to do this is to control how many times a given component is rendered, and assign data to the content of that component dynamically.

Components can be used to control small elements that hold data and work together to arrange the data into information. Pages need to display varying amounts of content, with conditional styling, consistently, across multiple screen sizes! A common use case would be to display images of items for sale in a consistent manner, and grey out the image when the last one has been bought, so a user knows the image is no longer available. However, we have no idea how many items are for sale, and this is where the relationship between short rows and components is strongest.

Note this component, which will display a single plant for sale at a plant shop:

import React from "react";

function PlantCard({plantDatum}) {
  return (
    <li className="card">
      <img src={plantDatum.image} alt={plantDatum.name} />
      <h4>{plantDatum.name}</h4>
      <p>Price: {plantDatum.price}</p>
      {true ? (
        <button className="primary">In Stock</button>
      ) : (
        <button>Out of Stock</button>
      )}
    </li>
  );
}

export default PlantCard;

This is going well, but what if we have more plants for sale? And maybe we don’t want to over-sell plants we don’t have in stock anymore—notice how we have a check for whether the plant is in stock. This is where a parent component that controls how many times to render a child component comes in.

import React from "react";
import PlantCard from"./PlantCard";

function PlantList({plantsData}) {

  if(plantsData === undefined){
    return null;
  }

  let plantCardItems = plantsData.map((plantDatum)=>{
   return<PlantCard 
    key={plantDatum.id}
    plantDatum={plantDatum}
    />
  })
  
  return (
    <ul className="cards">
      {/* render PlantCards components in here */}
    {plantCardItems}
    </ul>
  );
}

export default PlantList;

And higher up in the React component tree we actually have the request that populates plantsData:

useEffect(() => {
    fetch(backend)
      .then((response) => response.json())
      .then((data) =>setPlantsData(data))
  }, [plantsRefresh])

So over time, as more and fewer plants are loaded into the backend server, you’ll have more and fewer plants displayed on the website. This reminds me of how short rows achieve their color and shaping over time. As the work advances along the rows, you can see that short rows stack together to either shape the fabric or shape regions of color in the fabric.

Colorwork uses two or more colors and short rows to change colors on a curve that spans multiple rows. First one color is worked on partial rows looping back and forth, and then the second color is worked in partial rows that fill out a full row to fill in any gaps. The result is flat fabric that has an interesting color change behavior.short row colorwork example from Knitting with Henni
short row shaping example from Knitting with HenniShaping is a little more interesting because it essentially forces the plane of the fabric to traverse a sphere and *then* return to being a flat plane. This is useful for allowing extra room for chests and bellies in tops, bottoms and calves in hose/long johns, and heels in socks. Think about a sock with a differently colored heel. If it were just a tube, you’d have a bunch of extra fabric on top of the ankle, right? That’s both wasteful and uncomfortable. The correct way to solve this problem is to conditionally generate more fabric for the heel, and less fabric for the bridge of the foot, so that the sock conforms to the shape of the foot and the ankle.

React is capable of allowing us to force a webpage to dynamically conform to the shape of the available data in much the same way. It doesn’t make sense to generate a table that will have loads of extra cells for data that isn’t there, to ensure there is room for the data that is there. Instead, it’s better to conditionally generate HTML elements for each piece of data, and then control the flow of data and the presentation of the data so that the data becomes organized as information for the user.

Cables Are Like Passing State As Props

Cables are achieved by migrating sections of stitches at the insertion point out of order to each other, so that they can be acted on by instructions that apply at different parts of the row. In practice this feels much like braiding the fabric, but for the relationship to React, this also very much follows what is happening logically as one component updates a piece of state, and side effects cause further actions in another.

Some components act on each other in simple, one-to-one relationships such as controlling data access and access to server resources. This reminds me of a typical cable panel—a very common type of cable panel switches two different sets of stitches on rows 0 and 3, and continues in stockinette on rows 1 and 2. This creates the classic “cable chain” look with space between the braids allowing the tension of the switched stitches to gather in the fabric a little.
However, you can also pass these stitches over to these other parts of the rows and *then* apply other knitting techniques such as bobble stitching. Remember dynamically generating more components for each piece of data we wanted to display? Parent react components control generating many child components. Cables with bobble stitching in them are a perfect visual representation of how this works, because you pass in a section of stitches and then act on those stitches with separate, localized instructions. Then you *pass them back* when the panel repeats, and you can see that there is an expansion in the fabric in the bobble stitch.bobbled cable photo

Watch what happens as we pass state around our plant shop app:

First, we initialize a few pieces of state and then go get our list of plants from an outside resource. Note that we’re going to check our outside resource again based on a piece of state – plantsRefresh. Up until this point in our studies, we’ve requested data from outside resources and basically kept that data without really checking with that outside resource for new data. But that’s not how modern web apps work, in reality they want to share the latest version of the data with the user while they are still interacting with the app.

function App() {
  const backend = "http://localhost:6001/plants";
  const [plantsRefresh, setPlantsRefresh] = useState(false); //used solely to request a refresh of plants
  const [plantsData, setPlantsData] = useState(undefined);
  const [plantsFormData, setPlantsFormData] = useState(undefined);


  //When the app starts, I can see all plants.
useEffect(() => {
    fetch(backend)
      .then((response) => response.json())
      .then((data) =>setPlantsData(data))
  }, [plantsRefresh])

Just like passing groups of stitches over to use instructions for other parts of the row, we’re going to pass that state now into other components. Firstly, we’re going to use a control component to control how many times we render plants (only as many times as we have plants, and no more than needed).

This is the control component that controls how frequently to render a plant card:

import React from "react";
import PlantCard from "./PlantCard";

function PlantList({plantsData}) {

if(plantsData === undefined){
return null;
}

let plantCardItems = plantsData.map((plantDatum)=>{
return <PlantCard
key={plantDatum.id}
plantDatum={plantDatum}
/>
})

return (
<ul className="cards">
{/* render PlantCards components in here */}
{plantCardItems}
</ul>
);
}

export default PlantList;
This is the individual component we’ll render:


function PlantCard({plantDatum}) {
return (
<li className="card">
<img src={plantDatum.image} alt={plantDatum.name} />
<h4>{plantDatum.name}</h4>
<p>Price: {plantDatum.price}</p>
{true ? (
<button className="primary">In Stock</button>
) : (
<button>Out of Stock</button>
)}
</li>
);
}

See how as we hit the insertion point for all those plants, a ton of new elements are added to the page? Just like how we got to the edge of that cable stitch and added a bobble! Going to future rows will, to stretch the metaphor, control how many more or fewer or types of elements are on the page. Let’s do that now- we’re going to provision awareness for if new plants are added.

We’ll make our form submittable. Keep an eye on this state of newPlantObject , look to the right as when it gets changed we automatically add this to the server’s list of plants.

function NewPlantForm({setPlantsFormData}) {

function handleSubmit(event){
event.preventDefault();
let newPlantObject = {
"name" : event.target[0].value,
"image": event.target[1].value,
"price": event.target[2].value
}
setPlantsFormData(newPlantObject);
}


return (
<div className="new-plant-form">
<h2>New Plant</h2>
<form onSubmit={handleSubmit}>
<input type="text" name="name" placeholder="Plant name" />
<input type="text" name="image" placeholder="Image URL" />
<input type="number" name="price" step="0.01" placeholder="Price" />
<button type="submit">Add Plant</button>
</form>
</div>
);
}

export default NewPlantForm;
Remember plantsRefresh? here it comes into play again. We’ve passed state all around this component tree and and when it comes time to repeat this cable panel (or start rendering the whole app again), we’re going ready to go with the latest copy of the data (or our stitches in the right place to make the cable shape).

useEffect(() => {
if (plantsFormData === undefined) {
return null;
}

fetch(backend, {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(plantsFormData)
}).then(() => {
setPlantsRefresh(!freshenPlants);
})

}, [plantsFormData])

Thank you for reading. I hope you found this post entertaining and informative, and if you would like to talk more about the relationships between digital and textile programming please send me your comments down below!

Images and Resources Linked in this Post

Short Rows—Knit with Henni

Twisted Rib Cable Video—Expression Fiber Arts

Twisted Rib Cable Photo—Knit with Henni

Bobbled Cable Knitting Stitch—Knitting Bee

Related Posts