React - Week 1


Click here to see the Learning Objectives for this lesson.


Before you start#

Before you arrive at class you must have completed the following setup work.

React Preparation

If you are a teacher reading this, please check the Instructor Notes

What is React?#

React is a JavaScript library created by Facebook. It is used for making complex, interactive user interfaces. It has become very popular in the last 5 years.

Why has it become so popular?

  • It is fast and efficient
  • It is easy to understand & less verbose than the "vanilla" JS API
  • It helps separate functionality into small, understandable pieces

What is a component?#

React heavily relies on a concept called "components". Components are like small Lego blocks for designing and developing user interfaces (UI). They can be stuck together in different ways to create new UI.

Let's have a look at an example: the GitHub header. What are the logical "pieces" of UI? What could be a component?

Here we've highlighted some elements that could be components:

Component tips#

There are no hard & fast rules for making components. UIs can be split up into components in many different ways, requiring judgement based on your context.

  • Components should follow the Single Responsibility Principle
    • Each component should only have 1 "responsibility"
    • Should only do 1 thing
  • Components should have good, explicit names
    • This helps you to remember what the component's job is
Exercise A (estimate: 10 min)
1. Look at the example online shopping user interface in the Thinking in React article (the image at the top).
2. Draw boxes around the components and give them names. Compare with the example components shown in the second image.

Rendering with React#

Remember how annoying it was to manage the DOM yourself in our previous lesson? The "vanilla" JavaScript APIs for updating the DOM are quite long and difficult to remember. React makes this easier by manipulating each DOM element itself, instead of you doing it manually. You give React a "description" of the DOM that you want and it will update the DOM for you. React abstracts away the management of the DOM.

Let's take a look at an example. We are going to walk through how to render a <div> with the text "Hello World" within it.

First, lets recap how we could do this using "vanilla" JS (interactive version):

let divNode = document.createElement("div");
divNode.innerText = "Hello World";
let rootElement = document.querySelector("#root");
rootElement.appendChild(divNode);

Now let's convert to using React (interactive version):

const element = React.createElement("div", {
children: "Hello World",
});
const rootElement = document.querySelector("#root");
ReactDOM.render(element, rootElement);

JSX#

As you can see, React is already helping us a bit by cleaning up some of the verbose vanilla JS APIs. However in a typical React application you would still use a lot of the React.createElement function. To improve the developer experience the React team developed JSX.

JSX is a simple syntax sugar that looks like HTML, but is actually converted to the React.createElement function when you run it.

Using JSX (interactive version):

const element = <div>Hello World</div>;
const rootElement = document.querySelector("#root");
ReactDOM.render(element, rootElement);

As you can see, this is much easier to read than both the straight React.createElement API and the vanilla JS API. Most people using React use JSX to write their components.

Exercise B (estimate: 5 min)
Change the JSX example from above to instead render a h1 tag with the text "Hello Code Your Future".

Let's create a React app#

Exercise C (estimate: 10 min)
1. If you haven't already, follow the instructions to create a React app called pokedex.

What got created?#

Diagram of folder layout created by create-react-app. Click here for live diagram.

React Components#

We looked at the beginning of the lesson at the concept of components. Now let's look at how components are made in React.

import React from "react";
import ReactDOM from "react-dom";
function HelloWorld() {
return <div>Hello World</div>;
}
ReactDOM.render(<HelloWorld />, document.querySelector("#root"));

There are 3 important parts in this code:

  1. First we import React. This is important because JSX is converted to React.createElement calls. If the React variable is undefined then this will fail.
  2. We create a React component called HelloWorld.
  3. We render the HelloWorld component into the element with the id of root.
Definition

The process of rendering is turning the JSX elements returned by the component function into DOM elements on the screen. This is done by React for you.

Exercise D (estimate: 10 min)
In this exercise we replace the placeholder React app with our own. It should look like this:

Welcome to the Pokedex

Pokedex
1. In the pokedex React app that you just created, open the src/App.js file.
2. Delete everything in the file except the line containing export default App. You should see an error in your terminal and in your web browser - don't panic! We're going to remake the App component ourselves.
3. Import the React variable from the React package.
4. Create a function named App, which will be our component.
5. Within the App function, return a <h1> element with the text "Welcome to the Pokedex". What do you see in your web browser?
6. Create a <div> element that wraps around the <h1> you just created.
7. Below the <h1> element (but within the <div>), create an <img> element. Then make its src attribute equal to https://assets.pokemon.com/assets/cms2/img/pokedex/full/016.png. What do you expect to see in your web browser?
8. Now create a <header> element to wrap both the <h1> element and the <img> element.

Component Composition#

A component can be combined with another component so that both are rendered. This is called composition (interactive example):

function Greeting() {
return <span>Hello</span>;
}
function Mentor() {
return <span>Ali</span>;
}
function HelloWorld() {
return (
<div>
<Greeting />
<Mentor />
</div>
);
}

In the HelloWorld component we are using a reference to the Greeting and Mentor components. React reads these references when rendering HelloWorld and so it renders the Greeting and Mentor child components.

We are also using some shorter syntax within the HelloWorld component. <Greeting /> is just a shorter way of writing <Greeting></Greeting>, which is useful if we don't need to put anything inside the Greeting component.

Notice how the components that we write (HelloWorld, Greeting, Mentor) are written using a camel case convention and always start with an uppercase letter? And "regular DOM" components (div, span) are always lowercase? This is a convention to let you know whether you are using a "regular DOM component" or a component that you have written. When you're making your own components, you should always start them with an uppercase letter.

Exercise E (estimate: 5 min)
In this exercise, we will split out a new Logo component from the App component. And then we'll add a new BestPokemon component:

Welcome to the Pokedex

Pokedex

My favourite Pokemon is Squirtle

1. In your pokedex React app, open the src/App.js file.
2. Create a new function named Logo.
3. Copy the <header> element and its contents and paste it into the Logo component.
4. Replace the <header> element in the App component with the new Logo component.
5. Create a new component function named BestPokemon and return a <p> element with some text saying which is your favourite Pokemon (e.g. "My favourite Pokemon is Squirtle").
6. Render your new BestPokemon component below the Logo component within the App component.

Arrow Functions for shorter syntax#

Because a React component is just a function, we can also use the arrow function syntax:

const HelloWorld = () => {
return (
<div>
<h1>Hello World</h1>
</div>
);
};

This can be even shorter again if we use parentheses and implicit return:

const HelloWorld = () => (
<div>
<h1>Hello World</h1>
</div>
);

Although this is shorter, it is less flexible as we cannot insert code that is not JSX. Like for example, a console.log:

// THIS DOES NOT WORK!
const HelloWorld = () => (
console.log('Hello!');
<div>
<h1>Hello World</h1>
</div>
);

If we want to do this, we can still use arrow functions but we can't use the implicit return.

Exercise F (estimate: 5 min)
In this exercise, we'll convert the Pokedex app to use arrow functions. It should still look the same in your browser as Exercise E.
1. Using the pokedex React app that you created earlier, open the src/App.js file.
2. Convert the Logo and BestPokemon functions into arrow functions.

Embedding JavaScript into JSX#

So far all of the components we have looked at haven't been able to change - they are hard-coded. But this doesn't make very interesting websites, we want to be able to use variables with different data. We can insert variables (and some other things) into our React components.

Anything in the JSX that is inside curly braces {} is interpreted as a regular JavaScript expression. That means you can use every object or function from JavaScript that we have learned so far. Let's look at an example (interactive example):

function Greeting() {
const greetingWord = "Hello";
return <span>{greetingWord}</span>;
}

Now instead of hard-coding the greeting in the Greeting component, we are using a variable. Remember that everything between the curly braces is just regular JavaScript. So we can use more than just variables (interactive example):

function Mentor() {
const mentors = ["Ali", "Kash", "Davide", "German", "Gerald"];
return <span>{mentors.join(", ")}</span>;
}

Now we have modified the Mentor component to use the Array.join method so that it lists several mentor's names. This also works with other JS types:

function Addition() {
return <span>{1 + 2 + 3}</span>;
}
function Weather() {
const weatherData = {
temperature: 5,
location: "London",
};
return (
<p>
The temperature in {weatherData.location} is {weatherData.temperature}
</p>
);
}
function formatName(user) {
return user.firstName + " " + user.lastName;
}
function Name() {
const user = {
firstName: "Bob",
lastName: "Marley",
};
return <span>{formatName(user)}</span>;
}

A common pattern in React is to use Array.map to loop through a list of items and render a component for each one (interactive example):

const mentors = ["Ali", "Kash", "Davide", "German", "Gerald"];
function MentorsList() {
return (
<ul>
{mentors.map((name) => (
<li>{name}</li>
))}
</ul>
);
}

Here we are using Array.map to turn an array of strings into an array of components.

Exercise G (estimate: 10 min)
In this exercise, we'll change the Logo component to use a variable for the app name. Then we'll add a new component CaughtPokemon which displays today's date. And finally we'll make BestPokemon show a list of abilities:

Welcome to CYF's Pokedex

Pokedex

My favourite Pokemon is Squirtle

  • Anticipation
  • Adaptability
  • Run-Away

Caught 0 Pokemon on 4/9/2021

1. Using the pokedex React app that you created earlier, open the src/App.js file.
2. Inside the Logo component create a new variable called appName and assign it to "[YOUR_NAME]'s Pokedex".
3. Now replace the hard-coded app name with {appName}. What do you see in your web browser? What would you do if you wanted to change the app name?
4. Create a new component named CaughtPokemon. Within this component return a <p> tag with the text "Caught 0 Pokemon on" (we're going to fill in today's date in the next step).
5. Create a variable named date within the CaughtPokemon component, and assign it today's date (hint: new Date().toLocaleDateString()). Finally, render the date variable after the text "Caught 0 Pokemon on".
6. Render the CaughtPokemon component within the App component (below BestPokemon).
7. Within the BestPokemon component, create a variable named abilities and assign it to an array with some Pokemon abilities (e.g. ['Anticipation', 'Adaptability', 'Run-Away']).
8. Change the BestPokemon component to return a <div> element with the existing <p> element inside it. Then add a <ul> element underneath the <p> element.
9. Now use the .map() method on the abilities variable to loop over each name and return a <li> element for each (hint: look at the mentors list example above) within the <ul> element.

Keys#

You may have noticed that we are now seeing a red error message in the Dev Tools: Warning: Each child in a list should have a unique "key" prop.. This error happens when you use Array.map to return a list of elements (interactive example):

const mentors = ["Ali", "Sub", "Loic", "Anthony", "Lucy", "Mozart"];
function MentorsList() {
return (
<ul>
{mentors.map((name, index) => (
<li key={index}>{name}</li>
))}
</ul>
);
}

Here we have added a key prop to the li element. A documentation page explaining in more depth is in the further reading section but basically the key prop has a special meaning in React because it is used internally to keep track of which element in the list is which.

Importing/Exporting Components#

To help organise your code, components can be imported and exported just like any other JavaScript code (interactive example):

import Greeting from "./Greeting";
import Mentor from "./Mentor";
function HelloMentor() {
return (
<div>
<Greeting />
<Mentor />
</div>
);
}

We also need to export our components if we want to use them in other files:

function Greeting() {
return <span>Hello</span>;
}
export default Greeting;

The convention is to name component files exactly the same as the component (including the capital letter).

Exercise H (estimate: 5 min)
In this exercise, we'll split the Pokedex app into separate files. It should still look the same in your browser as Exercise G.
1. Open the pokedex React app that you created earlier.
2. Create a new file within the src directory named Logo.js.
3. Copy and paste the Logo component from App.js into Logo.js.
4. Remember to add import React from 'react' at the top of Logo.js.
5. Export the Logo component from Logo.js (hint: look at the Greeting example above).
6. Delete the old Logo component from App.js.
7. Import the Logo component into App.js (hint: look at the HelloMentor example above).
8. Repeat this process with the BestPokemon and CaughtPokemon components. What do you think the files should be called?

Making an argument for Props#

What's the problem with our HelloMentor component above?

The component HelloMentor is very static. What if we want to say hello to a different mentor? Currently, we would have to change the code too! This is easy in our tiny application but for "real" applications this might be more difficult.

Instead wouldn't it be good if we could change which mentor we are saying hello to every time we render the component? So we could reuse the HelloMentor component for different mentor names. This is what props are for.

What are Props?#

Props are what we use in React to pass "arguments" to components. They are very similar to arguments in functions - you can "pass" props to components, and you can use those props within a component.

First let's look at passing props to your components (interactive example):

<Mentor name="Mozafar" />

As you can see props are key-value pairs, in this example the key is name and the value is the string 'Mozafar'. We can pass as many props as we like to a component.

We don't have to use strings, we can use any valid JavaScript data like numbers, arrays and objects. Remember that in JSX you can use curly braces {} to inject data that is not a string:

<Mentor age={30}>

Now let's take a look at using props that we have passed to a component (interactive example):

function Mentor(props) {
console.log(props);
return <span>{props.name}</span>;
}

React gives you access to props in the first argument to the component function. We can then inject props into our component using curly braces.

The props variable is just a normal object with key-value pairs that match what was passed to the component. Because it is just a variable, it can be used like any other variable. That includes injecting props into attributes:

<div id={"mentor-id-" + props.id}>{props.name}</div>

Or calculating new values:

<div>{props.age + 1}</div>
Exercise I (estimate: 10 min)
In this exercise, we'll move the variables in Logo, BestPokemon and CaughtPokemon to the App component. Then we'll make App pass those variables as props to the sub-components. Your app should still look the same in your browser as Exercise H.
1. Using the pokedex React app that you created earlier, open the App.js file.
2. Pass a prop appName="Pokedex" to the Logo component.
3. Now open the Logo.js file.
4. Delete the appName variable. What do you see in your web browser? Why?
5. Change the Logo function to access the first argument and call it props. Use console.log to inspect the props variable.
6. Change the usage of appName in the <h1> to be props.appName instead. Does this fix the problem? Why?
7. Now open the BestPokemon.js file.
8. Copy the abilities variable and then delete it from BestPokemon.js.
9. Paste the abilities variable into App.js.
10. Pass the abilities variable as a prop to BestPokemon from App.js.
11. In the BestPokemon.js file replace the existing usage of abilities with the abilities prop. You should still see the Pokemon ability names in your web browser.
12. (STRETCH GOAL) Repeat the process with the date variable in the CaughtPokemon.js file.

Credits#

Inspiration & examples for this module were taken from Kent C. Dodd's Beginner's Guide to ReactJS course.

Coursework#

Click here to view the coursework for this lesson.

Feedback#

Please spend two minutes reviewing this lesson to help us improve it for the future. This feedback will be shared with volunteers.