You can access the full course here: Bite-Sized React
Table of contents
File & Base Setup
In this lesson, we use what we’ve learned about JSX to build a composable UI using the example of a Tweet!
The Tweet structure will have an Avatar, Name, HandleName, Relative Time, Message, and 4 Icon Buttons.
Just as we discussed in detail in the HelloWorld section, make sure you have your Terminal open and are in the directory where you want to create your new project. In the video lesson a project directory on the Desktop called React is used to hold all course projects (you can choose any directory location and name). Use your terminal to change into your project directory.
Now that your terminal is in the project directory, use the Create-React-App command to begin a new project. In the terminal, enter the command:
npm init react-app static-tweet && cd static-tweet
This command will create a basic working React app called static-tweet, install our dependencies from NPM and finally change the working directory to be our new project inside the terminal.
The generated project contains some files we won’t be using for this demo so you can ignore them or delete them with this command:
rm src/App.* src/logo.svg src/s*.js
Open your project in VS Code. Either open the application VS Code and use File/Open from the menu or type the following into the terminal:
code .
In the video lesson we start by adding FontAwesome to our React project. FontAwesome gives us access to the icons we will use in this lesson for buttons we are creating. To access these icons we will need to add it as a stylesheet in our index.html file. In VS Code, open the index.html file in the public folder to add this link statement:
<!-- index.html --> <link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.0.12/css/all.css"/>
Place this stylesheet link in the <head>
section of index.html just above the <title>
tag:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8" /> <meta name="viewport" content="width=device-width, initial-scale=1" /> <!-- (start) FontAwesome link - add this line to include Icons --> <link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.0.12/css/all.css" /> <!-- (end) FontAwesome link --> <title>React App</title> </head> <body> <noscript>You need to enable JavaScript to run this app.</noscript> <div id="root"></div> </body> </html>
You can browse or search for icons on the FontAwesome website: https://fontawesome.com/icons?d=gallery&m=free.
In VS Code, open the src/index.css file and add the styles for a tweet class by copying from the course download files or text below:
/* index.css */ .tweet { border: 1px solid #cccccc; width: 564px; min-height: 68px; padding: 10px; display: flex; font-family: "Helevetica", arial, sans-serif; font-size: 14px; line-height: 18px; }
While CSS is outside the scope of this course, including the CSS from the download files will make your app look better by adding border, width, height, font style and padding around our tweet element.
Tweet Component
Next, we’ll setup our src/index.js file in a similar way as we did in the HelloWorld lesson. Start by deleting all the contents and then import React and ReactDom modules as well as the index.css we created above.
// index.js import React from 'react'; import ReactDOM from 'react-dom'; import './index.css';
React will need to be imported into all files that use React.
ReactDom is needed only needed in this index.js file to render the React code to the web page HTML known as Document Object Model (DOM).
Note: Notice that the CSS is imported in a different way. The first thing to realize is that we are importing the entire index.css file and secondly notice that it is not simply imported using a string (which is interpreted as a node dependency like ‘react’). We actually import a relative path ‘./’ (meaning in the same directory as current file) and use the file extension ‘.css’ otherwise ‘.js’ would be assumed.
Tweet Component
Next create the Tweet Component just like we created the HelloWorld component in a previous lesson.
// index.js function Tweet() { return ( <div className="tweet"> Tweet </div> ); }
Note: In the JSX lessons, we noted that while JSX is a HTML-like syntax there are a couple things to watch out for. One is that while we would reference a class in HTML with the class keyword, we cannot do that in JavaScript (JS) since class is a JS keyword. React instead uses className.
Finally, we add our render logic and our index.js file now looks like this:
// index.js import React from "react"; import ReactDOM from "react-dom"; import "./index.css"; function Tweet() { return <div className="tweet">Tweet</div>; } ReactDOM.render(<Tweet />, document.querySelector('#root'));
Test the App
In the terminal, start the app by typing:
npm start
You see your Chrome browser open up to localhost:3000 and display something like this:
Open Google Developer Tools by inspecting the page. Under the Elements tab notice in the <head>
of the document there is a <style>
tag that we didn’t put there. This is the contents of our index.css we imported into our index.js JavaScript file.
Tweet Sub-Components
Next, it’s time to build some components that will be composed together inside the Tweet Component.
Let’s start with Avatar which will be a component that returns an <img>
tag. Code the following function inside index.js:
// index.js function Avatar() { return ( <img src='https://gravatar.com/avatar/nothing' alt='avatar' className='avatar' /> ); }
Next, add some CSS to our index.css file for the class of avatar:
.avatar { width: 48px; height: 48px; border-radius: 5px; margin-right: 10px; }
Lastly, we can now modify our Tweet Component to use the Avatar Component alongside the word Tweet:
// index.js function Tweet() { return ( <div className='tweet'> <Avatar /> Tweet </div> ); }
Finally, with the render logic included, our index.js file now looks like this:
// index.js import React from 'react'; import ReactDOM from 'react-dom'; import './index.css'; function Tweet() { return ( <div className='tweet'> <Avatar /> Tweet </div> ); } function Avatar() { return ( <img src='https://gravatar.com/avatar/nothing' alt='avatar' className='avatar' /> ); } ReactDOM.render(<Tweet />, document.querySelector('#root'));
Our browser output now looks like this:
Open the Chrome Developer Tools and select the Components tab. As discussed in the Getting Started section, the Components Tab is installed with the React-Developer-Tools and allow us to view React in terms of components. In other words, we see the app the way React sees it.
Notice our Tweet is now composed of two components; the parent Tweet and child Avatar.
Final Details
In the last lesson we started to build our static tweet. We got as far as putting our Avatar within our Tweet. Next, we’ll add the Message, Time, Name and Handle components.
Keep in mind our desired Tweet Structure, let’s first code our static Message Component, we’ll simply return a string of text ensuring we wrap the text in a <div>
(because we want it on its own line) and provide a className so we can add CSS style. Ensure to copy the CSS from the course download files in the static-tweet directory in the src/index.css file.
// index.js function Message() { return ( <div className="message">This message is less than 140 characters!</div> ); }
Next, let’s code our NameWithHandle Component:
// index.js function NameWithHandle() { return ( <span className="name-with-handle"> <span className="name">Your Name</span> <span className="handle">@yourhandle</span> </span> ); }
The CSS to style name and handle; added to our index.css is:
/* index.css */ .name { font-weight: bold; margin-bottom: 0.5em; margin-right: 0.3em; } .handle { color: #8899a6; font-size: 13px; }
Next, let’s code the Time Component:
// index.js const Time = () => <span className="time">3h ago</span>;
We can also construct simple components are variables set equal to an arrow function that returns JSX. As long as the JSX returned is valid, React don’t care if we use a variable or a regular function.
For Time we provide the following CSS in index.css:
/* index.css */ .time { padding-left: 0.3em; color: #8899a6; } .time::before { content: "