Lambda School: Full Stack – Unit 2, Sprint 6: React Components and Component State [1 of 2]

React is a JavaScript library developed by Facebook to rapidly generate user interfaces. Its the most popular front-end JavaScript library in the world right now, and has been for some time. Previously, we learned how to build components with JavaScript that make use of separate HTML, CSS and JavaScript files to essentially build functions that output specific content onscreen. For example, a menu can be a component, or a carousel, or another specific part of a web page like a product list.

This was all made possible by DOM manipulation, with syntax like document.getElementByClassname and so on. It can be a tedious process to build components in this manner, combining code from .js files, .html files and .css files to render a single part of a page. React simplifies this process by allowing a single file to contain both the logic necessary to work with data and perform user interactions on a page with the markup and styling needed to render it onscreen. It essentially takes the HTML, CSS and JavaScript and allows them to cohabitate a single file. By doing so, components become centralized, so they’re easier to manage. It also allows applications and components to call on other components, in exactly the same manner as imports and exports from JavaScript, which also simplifies the implementation of components and features in an application.

Sprint 6-1

A key feature of React is the use of state, which is data that determines what is rendered onscreen. In complex user interfaces, like that of Facebook or YouTube or Twitter, there are many elements rendered onscreen onscreen. Facebook might have status updates, a component to post, a sidebar with groups and pages, a section with ads, and more. YouTube has a video, a section with comments, likes and dislikes, a subscription button, a sidebar with other videos, a sidebar with other channels and with controls pertinent to the logged-in user’s own channel and viewing history, and so on. All of these elements make use of current data, a.k.a. state.

Being logged in or logged out changes the state of FB, Twitter or YouTube. It determines whether the use sees a register/login screen or has access to the user’s account. A friends list might be loaded into state, which determines what posts are onscreen in Facebook. Clicking on a group changes state to show a different set of posts and changes the location of where the current user is posting to. Adding a filter to a video search on YouTube changes the sort, which re-renders videos based on time and date uploaded; selecting a channel changes the state of the videos displayed onscreen to show only that channel’s videos. Clicking “playlists” further filters the videos and updates state to show only the given channel’s videos for a particular playlist, and so on.

All of this rendering and re-rendering places a heavy burden on the DOM, which can affect page performance. This data is updated in real-time, with every click potentially every aspect of a page. React offloads a lot of this burden from the DOM by managing the state that applications rely on to render onscreen. It does this by way of an engine called the virtual DOM.

The virtual DOM acts like an intermediary between the DOM and the data it needs to render a web page. It “reacts” to changes in state and lets the DOM know what needs to be updated on a page. However, instead of updating an entire page and having to request data from a server across the internet to render a page anew each time there’s a change, the virtual DOM detects changes to a page’s state and then tells the DOM specifically which nodes have need to be updated, accordingly. This process is called reconciliation. The DOM then updates only those nodes, instead of refreshing the whole web page. It relieves a great deal of pressure from the DOM and makes rich, stateful applications possible.

Components

Components are the building blocks of React. There are several types of components, but they fall into two basic categories: stateful components and function components. As the name implies, stateful components hold state, and function components do not. Function components display state on the DOM but don’t manipulate it in any way.

import React from 'react';

const Metal = () => {
  return (
    <div>
      <h1>SLAYER!!!<h1>
      <img src='horns.jpg alt='hand making heavy metal horns gesture' />
    </div>
  )
}

Above is an example of a React component. What’s interesting about it is that it appears to combine two different languages. The top looks like a JavaScript import and a function and the bottom looks like HTML, with a <div> and <h1> and <img>.

The HTML is actually a language called JSX, or JavaScript Extension. It uses JavaScript to emulate HTML (its basically DOM manipulation, but with an interface that looks like HTML). Because its JavaScript under the hood, it can also include actual JavaScript – including variables and functions and the like.

That said, React components are just JavaScript functions. Adding JSX to the mix makes writing code to render elements onscreen easier. Instead of the more convoluted DOM syntax that we used previously, we can essentially use HTML-like code to create page elements. We can use inline styling to style the JSX, or we can import CSS, or we can even use what’s referred to as CSS-in-JS libraries like Styled Components to include CSS inside of the given component. It took me some time to get used to this method of building, but now, I actually prefer it to the traditional separation of HTML, CSS and JavaScript.

All of this means that application logic AND the code that renders it and styles it can live together, making self-contained components possible. This means that its also very easy to swap out components or reuse them in other applications.

JavaScript

To include JavaScript in JSX, we have to enclose it in curly braces. This can be any JavaScript, from a variable name, to an expression, to a function. Here’s an example related to the code from above:

import React from 'react';

const Metal = () => {
  const band = 'SLAYER!!!';
  return (
    <div>
      <h1>{band}<h1>
      <img src='horns.jpg alt='hand making heavy metal horns gesture' />
    </div>
  )
}

The output is the same, but note that the <h1> now holds a variable instead of the text string that it had before. Using JavaScript inside of JSX is called escaping. To escape, we nest the JavaScript inside of the “HTML” and enclose it in curly braces. So, just like with DOM manipulation, we can use React to compute the content of our “HTML” instead of having it hard-coded inside of the tags. The syntax is much easier for us to write and follow though – and easier to edit!

Design Philosophy

Two major React design tenets that we learned about at Lambda are (1) the separation of concerns and (2) declarative programming.

The “separation of concerns” is a design philosophy that states that each piece of code should do one and only one thing. Its meant to simplify functions and lead to cleaner code. It also helps with debugging, as a function with one specific purpose is much easier to understand than one that does a myriad of things. They’re easier to test as a result, too.

I’ve heard of this design philosophy before, and my initial issue with React’s implementation of it was that to me, having distinct HTML, CSS and JS files was an implementation of the philosophy. We were isolating the markup, the styles and the logic from each other. The React team had a different interpretation, however. As per the Lambda text:

They argue that we can’t truly separate a <button> tag from the function the button invokes. Separating the two, one in an HTML file and another in a JavaScript file, isn’t a separation of concerns, it’s cutting one concern in half and then putting one half in the bedroom and the other half in the garage. It’s a headache we don’t need.

At first, wrapping my head around this in a practical way was difficult. I understood the theory that was proposed, but writing React was just alien to my way of thinking, especially after the feelings of accomplishment of actually learning DOM manipulation. Later on, however, as I worked on more React applications, I began to appreciate this way of thinking more. Managing props and state and knowing where I can and can’t place JavaScript in a component that includes JSX was frustrating, but with time, its become more of a default to me. The syntax is much more straightforward than the JavaScript I was using to affect the DOM, thanks to JSX, and with the use of Styled Components, I have access to everything – page elements, styles and logic – all from one place.

I love that I can use JavaScript in JSX. It makes more sense to me now, when I look at what I write, to have a function that iterates over data (like .map) and include its output inside of JSX. In many projects now, I’ve mapped over data from an API and returned JSX for each item in the array. Even though my JavaScript isn’t strong yet, React has helped me to make it a little hardier.

The second design tenet is the idea of imperative programming vs. declarative programming. Imperative programming is what we’ve been using with our JavaScript to date. Its an explicit way of coding, but it can be difficult to write and lead to code that’s harder to understand. Declarative programming, which is the type that React employs, tells a computer what we want it to do, not necessarily how we want it done in detail.

The example we were given to look at dealt with doubling an array. Using an imperative approach, we might have code that looks like this:

let numbers = [1,2,3,4,5];

for (i = 0; i < numbers.length; i++) {
  numbers[i] = numbers[i] * 2;
}

A declarative approach, on the other hand, could look like this:

const double = number => number * 2;

numbers.map(double);

While there’s nothing wrong with the first approach, I think that the second approach is easier to follow. We have a function that multiplies a number by 2. We use that function to map through an array. The imperative example goes through a lot more setup.

The Lambda text does inform us that at lower levels, all code is imperative; but also says that with practice, declarative code is easier for us to read. The importance of this comes in the workplace, where, apparently, we’ll spend more of our time reading other people’s code and trying to understand it than we will writing our own code.

Ok. I’m breaking from this for a bit. This first React lesson goes through a lot, and we haven’t dug into state just yet. I’m going to split this post into two parts and cover that in the next one.

One thought on “Lambda School: Full Stack – Unit 2, Sprint 6: React Components and Component State [1 of 2]

Leave a comment