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

This post continues my review/recap of the first React lesson in Lambda School’s fullstack web developer track. You can find the first part here.

Web applications are driven by state, which is the data needed to render components onscreen. As state changes, components update to reflect these changes. In the previous post, we looked at some examples of state – not code, but examples of state onscreen and what it could change, like status updates (posts), lists (groups and pages), images (ads) and smaller sections of an interface, such as the number of likes or dislikes on a post or video, a subscribe button with the number of subscriptions and even the state of an entire application based on whether a user is logged in or not.

The Lambda text gave some real-world examples that weren’t computer-based. For example, a traffic light has three possible states: red, yellow or green. The simplest state is on and off, like a light bulb or any other binary/boolean. An application, like a to-do list, could potentially have a state of “three to-do’s, none of which are complete”. Completing one of the to-do’s changes the application’s state, as does turning a light on or off, or a traffic light changing from red to green.

Sprint 6-1

React Hooks

Components let you split the UI into independent, reusable pieces, and think about each piece in isolation.

– Components and Props, reactjs.org

The traditional way of writing stateful React components was to use class components. These are like JavaScript classes and look like this:

class BigFour extends React.Component {
  render() {
    return <p>One of the Big Four of thrash metal is {this.props.band}</p>
  }
}

Lambda actually didn’t begin teaching React to my cohort using class components. I think previous cohorts did start with it, however. When I started Lambda, React Hooks had just been introduced to the world. Hooks are a way of making function components stateful. They’re a simpler way to write components and were named because they allow function components to “hook into” React state and lifecycle features. Hooks don’t work in class components – they can only be used in function components, so state can be used without classes.

This is the the hook equivalent of the class component above:

function BigFour(props) {
  return <p>One of the Big Four of thrash metal is {props.band}</p>
}

As we can see, “class” has been replaced by “function”, we’re no longer extending React.Component, the render() method isn’t needed and “this” is no longer needed to bind props to the function. We also name “props” where the function takes in data, whereas in the class component we don’t do this – I think its automatically assumed that props would have to be brought in and bound to the class with “this”. Just doing away with worrying about “this” is a big improvement, to me. We’ll talk about props shortly.

Props and State

Function components can make use of the state hook to gain access to state. All hooks in React begin with the word “use” and then the name of something it provides access to. In this case, to use state, the hook is literally called “useState“. Its typically imported into a function component like this:

import React, { useState } from 'react';

Its imported from React inside of curly braces because its a single component from React. I’ve also imported it like this, with another hook, and its worked:

import { useState, useEffect } from 'react';

Once useState has been imported from React, the way its initialized and updated (usually right at the start of the function) looks like this:

const [name, setName] = useState();

Its a strange line, for people who are seeing it for the first time, but this is what it means:

  1. name is the name of the variable/piece of state
  2. setName is the name of a function that can update name
  3. useState() is the hook that lets the component use state to begin with

Another example could be:

const [quantity, setQuantity] = useState();

In the above example , we have a quantity of some kind that can be updated by calling the setQuantity function. Its a common convention to name the function that can update state with the word “set“. We don’t have to do it, but its something that’s encouraged, and I haven’t seen anyone not use this format. So, “numberOfLikes” is updated by “setNumberOfLikes” and “favoriteBand” is updated by “setFavoriteBand” and so on.

We can also specify an initial value for state inside of the parenthesis of the useState() hook. Consider these:

const [name, setName] = useState(''); // sets name to a blank string
const [name, setName] = useState('Takeshi Kovachs'); // sets name to Takeshi Kovachs
const [quantity, setQuantity] = useState(0); // sets quantity to 0
const [items, setItems] = useState([]); // sets items to an empty array

The setState function that we specify with the useState hook isn’t actually written by us anywhere in the application. Whatever we name it, its used by React to update the piece of state that its associated with, so the inner workings of that particular function is already defined by React.

Updating state

We can’t update state by directly assigning a new value to it.

name = 'Lews Therin Telamon Kinslayer'; // won't update the slice of state called "name".

Instead, somewhere in our code, when we want to update the slice of state called “name”, we have to use setName(), like this:

setName('Lews Therin Telamon Kinslayer'); // this WILL update state

So, “name” is a variable. Its a slice of state (which basically means a variable that’s held in state). We initialized its value as a blank string with “useState(”);” in an example above and as the main character from Altered Carbon with “useState(‘Takeshi Kovachs’);” in another example. The function that can change its value is called “setName”.

Why is this important?

So, now, why is state important? What makes it different from just using a regular variable? I was confused about this at first, too, until I finally learned that updating state causes the rest of an application to render or re-render as needed. State is a centralized variable. If its used only in a single component, its called component state. If its used in more than one component, its called application state. Updating state causes the components which use it to render, so it gives us essentially a “single source of truth” for a given “variable”.

React essentially “reacts” to state. State is what makes React render with up-to-date information.

That’s another important characteristic of state. Updating it changes it at the top level, where it was originally defined, then the new value filters down to any components that make use of that slice of state. In this way, all of an application is always working with the most current value for any given slice of state.

So, while variables in JavaScript components might live inside of those components, state can actually be passed around a React application – passed down, from parent to child, really. If its updated, that update is sent to the top and recirculated to any components that use it (useState) and it causes them to re-render with new state.

Props

So, how do we actually pass state down from one component to another? We do it using props, which means “properties” and looks just like an HTML attribute. React components are called from inside of JSX. They look like self-closing HTML elements with proper names (capital letters). Using our BigFour component from way at the top of this post would look like this:

<BigFour />

It would have to be inside of the return() statement in a React component, and if it wasn’t the only thing being returned, it would have to be nested inside of a container. Whenever you’re returning more than one element in JSX, they have to be inside of a container, so if BigFour were accompanied by a title, they’d have to be grouped like this:

return (
  <div>
    <h1>Thrash Metal</h1>
    <BigFour />
  </div>
)

But, this alone wouldn’t tell us who any of the BigFour are. We can provide that information via props, which, as stated, look like HTML attributes. For example:

return (
  <div>
    <h1>Thrash Metal</h1>
    <BigFour band='Slayer' />
  </div>
)

We can even call the same component multiple times, if needed, like this:

return (
  <div>
    <h1>Thrash Metal</h1>
    <BigFour band='Metallica' />
    <BigFour band='Megadeth' />
    <BigFour band='Slayer' />
    <BigFour band='Anthrax' />
  </div>
)

The function itself, if you remember, takes in props, which can hold any number of variables in it, and in its return statement, it used {props.band} in curly braces to allow it to include JavaScript in its JSX/HTML, like this:

function BigFour(props) {
  return <p>One of the Big Four of thrash metal is {props.band}</p>
}

We could conceivably even read in an array of the big four and map() through it and output the component once for each band in the array. But, the important thing here is that one component called another component, passed state data to it in the form of props and let that second component render using that data.

When state is inside of a component and is being managed by a component, its called state. When it (or other variables) is passed from a parent component to a child component, its called props. Props from a parent component can even be used to set state on a child component. We’ll delve into this more in the next post.

Conditional Rendering

Conditional rendering is the process of rendering a component based on a condition – in the case of React, its generally based on state. If state is X then return something, or some component. If state is Y then return something else or a different component. It seems pretty straightforward, and it basically is. What caught me, when I refactored my portfolio from vanilla JavaScript to React, is that you can’t use if..else statements in JSX, even inside of curly braces. I don’t know the reason for this yet. What you can use in their place are ternary operators (essentially another incarnation of an if..else statement) or switch statements.

return (
  {coinToss === 'heads' ? <Heads /> : <Tails />}
)

I haven’t used ternaries a lot yet, but I do need to get more accustomed to them. What we have above is a conditional that says that if a coin toss returns “heads” then render the <Heads> component, else render the <Tails> component.

In my portfolio, I used switch statements coupled with an event listener (called an onClick in React) to render components based on a click. One of them (the one that switches between front-end, back-end and about-me components looked like this:

_renderSubComp(){
    switch(this.state.render){
        case 'frontend': return <Frontend />
        case 'backend': return <Backend />
        case 'about': return <About />
    }
}

It was in a class component, which is why I have to bind state to “this” but the part we want to look at here is the switch(variable) and the case conditions, which tell the switch which component to render. These function components just pasted info onscreen. They didn’t need props to work, as their data is static.

Clicky clicky

So, since web applications are made up of state and things that change state, we need to look at one of the most important methods of changing state: user interaction. In this case, the onClick event – React’s click listener.

onClick takes a callback function which it executes if the element its attached to is clicked. Especially when it comes to adjusting state, we can’t just assign state a new value with a click. It has to be in the form of a function, or it will turn into an infinite loop in which state is constantly being updated and rendered.

<div onClick={ setQuantity(quantity + 1) } className="Count"> // infinite loop

<div onClick={ ()=> setQuantity(quantity + 1) } className="Count"> // working function

One final note: last year, in a JavaScript post, I shared the “!” or what my first TL called the bang. It turns a variable or statement into its opposite, so true and !true are opposites. This can be used with a setState function that’s updating a boolean, to essentially switch its value to the opposite – so essentially its an on/off switch. In the code-along project in the Training Kit, it was used with a lightbulb application to change state from lightOn to !lightOn, so if the switch was on, it would turn off, and if it was off, it would turn on. Experiment with this, because its late for me and I’m done typing.

Leave a comment