Merge pull request #3 from FrontEndFoxes/feature/react-chapter

Feature/react chapter
pull/313/head
Jaeriah Tay 5 years ago committed by GitHub
commit af1575ba5f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -0,0 +1,337 @@
# Scaffold a React.js app: Introduction to React.js; JSX, Scaffold your site
### Introduction
In the previous web application projects, we learned how to build fully functional applications that runs directly in the browser using static HTML, CSS, and JavaScript. In this next chapter, we'll be using React, a declarative, efficient, and flexible JavaScript library for building modern user interfaces and web applications. It is a very popular choice when building a SPA, Single Page Application. Frameworks and libraries are commonly used in modern web applications because of the ease of starting a new project. A scaffolded project normally would have configurations, toolings and dependencies already set up and installed for you. We will be taking a practical approach by builidng a project to learn React as a frontend library and will also be linking resources such as the React documentation, for further reading. Throughtout the chapter, we will introduce concepts such as JSX, components, props, state, and lifecycle.
In this lesson, we'll be setting our React application using `create-react-app` and using a Tailwind for styling. This lesson is the first of three lessons in the React chapter where we will first scaffold the React project, install necessary tooling and libraries, one of which is TailwindCSS, a CSS utility library and build out the structure of the porfolio.
### Prerequisites
As this is the last chapter of the curriculum, prerequisites are all the chapters leading up to this React chapter.
- Basic familiarity with HTML & CSS.
- Basic knowledge of JavaScript and programming.
- Basic understanding of the DOM.
### Preparations
You need a local web server to test the web app we'll build in this lesson. If don't have one, you will need to install [Node.js](https://nodejs.org).
- Node.js. Make sure you version of Node.js is at least 12, or the latest stable release.
- Preferred code edition or IDE
- Terminal. MacOS and Windows both have built-in terminals. If you're using a code editor like VSCode, it also has conveniently built-in terminal.
- React devtools is recommended. It is a web browser extension that helps with developing and debugging when using React.
## Project Setup
### Install React
First, we're going to boostrap the React project by installing it from our Terminal. React has a handy command `create-react-app` to run whereby it will bootsrap a starter project with all the necessary dependencies installed. You can read more about Create React App [here](https://github.com/facebook/create-react-app) Open your preferred terminal and run:
```bash
npx create-react-app portfolio
# OR
npm init react-app my-app
# OR
yarn create react-app portfolio
```
The first couple of keys runs and installs React and the `portfolio` is the name of your directory. It can be anything you decide to name it, but for simplicity sake let's call it `portfolio`. [npx](https://medium.com/@maybekatz/introducing-npx-an-npm-package-runner-55f7d4bd282b) is a package runner tool that comes with npm 5.2+ and higher. Running one of the above commands will create a directory called `portfolio` inside the current folder (usually your home directory).
Once the installation is done, change directory into your project folder and open the project up in your code editor.
```bash
cd portfolio
```
### React project structure
Inside that directory, it will generate the initial project structure and install the transitive dependencies:
```
portfolio
├── README.md
├── node_modules
├── package.json
├── .gitignore
├── public
│ ├── favicon.ico
│ ├── index.html
│ └── manifest.json
└── src
├── App.css
├── App.js
├── App.test.js
├── index.css
├── index.js
├── logo.svg
└── serviceWorker.js
└── setupTests.js
```
The public folder contains our assets, html static files and custom client side javascript files. package.json is used by npm (Node package manager) to save all the packages needed to deploy our app, but we don't have to worry about this because CodeSandbox installs and updates this file for us.
In our public folder, we have a standard html file called index.html. This is our point of entry file where we have our root element, which is named by convention. If you scroll down to line 30 in the body element, you will see <div id="root"></div>. This is the root element where we will be injecting our application.
The src folder contains all our React code and houses our index.js, app.js and later on our components when we start to create them. In index.js, you will see something like this:
```js
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
ReactDOM.render(
<React.StrictMode>
<App />
</React.StrictMode>,
document.getElementById('root')
);
```
Here we import the React library and we use the ReactDOM render() method in order to print the contents of our App component into the root div in our index.html that we specified above. Our main app component App.js has to be imported as well to be included in the render. The App.js component is passed in as the first argument in the render function and the rootElement as the second argument. That will tell React to render the app component and transform it into an element using the React.createElement method at build time to the index page. We will be stripping out all the scaffolded code in the component App.js and rebuilding it later on.
```js
import logo from './logo.svg';
import './App.css';
function App() {
return (
<div className="App">
<header className="App-header">
<img src={logo} className="App-logo" alt="logo" />
<p>
Edit <code>src/App.js</code> and save to reload.
</p>
<a
className="App-link"
href="https://reactjs.org"
target="_blank"
rel="noopener noreferrer"
>
Learn React
</a>
</header>
</div>
);
}
export default App;
```
The `App` function in App.js represents a React function component. In React, components can be defined as class components or function components. We will get into explaining more about these components in the next chapter when we start building out more components. You can create your components as a individual files (Single File Component - SFC). In React, html-like tags which are what we call JSX can be passed in the return statement to be returned. The JSX inside the return function is what the App.js will render out. JSX stands for JavaScript XML and is a syntax extension to JavaScript that allows you to write markup inside a React component.
### Set up TailwindCSS and SASS
Before we go any further, let's install [TailwindCSS](https://tailwindcss.com/), the CSS utility library we will be using for styling of this project. Tailwind CSS is a highly customizable, low-level CSS framework that gives us all of the building blocks we need to build intuitive user interfaces. So, it is simply a utility first CSS framework. We want to write our CSS using SASS, a CSS compiler so that we can easily nest our styles seamlessly. Let's install Tailwind and the node-sass package:
#### Install Node SASS
```bash
npm i sass
# OR
yarn add sass
```
#### Install Tailwind
```bash
npm i tailwindcss autoprefixer postcss-cli
# OR
yarn add tailwindcss autoprefixer postcss-cli
```
More details on [here](https://tailwindcss.com/docs/installation).
Now, we need to generate the configuration for tailwind which will create a minimal `tailwind.config.js` file at the root of your project:
```bash
npx tailwind init
# OR
npx tailwind init --full # with all default configuration
touch postcss.config.js
```
#### Install and configure CRACO
After running the above commands, the `tailwind.config.js` file is created which contains all our default configuration. Next we need to install [CRACO (Create React App Configuration Override)](https://github.com/gsoft-inc/craco), an easy and comprehensible configuration layer for create-react-app, because Create React App doesn't let you override the PostCSS configuration natively.
```bash
npm install @craco/craco
# OR
yarn add @craco/craco
```
When the installation is complete, update your scripts in your `package.json` file to use `craco` instead of `react-scripts` for all scripts except eject:
```diff
"scripts": {
- "start": "react-scripts start",
- "build": "react-scripts build",
- "test": "react-scripts test",
+ "start": "craco start",
+ "build": "craco build",
+ "test": "craco test",
"eject": "react-scripts eject"
},
```
Now, create a `craco.config.js` at the root of our project and add the tailwindcss and autoprefixer as PostCSS plugins:
```bash
touch craco.config.js
```
```js
// craco.config.js
module.exports = {
style: {
postcss: {
plugins: [
require('tailwindcss'),
require('autoprefixer'),
],
},
},
}
```
#### Purge styles and include Tailwind in CSS
Because Tailwind is a library with default utility classes, CSS will be need to compiled for production. It is good practive to purge your project of unused styles in production builds so that load time is faster In your tailwind.config.js file, configure the purge option with the paths to all of your components so Tailwind can tree-shake unused styles in production builds:
```diff
// tailwind.config.js
module.exports = {
- purge: [],
+ purge: ['./src/**/*.{js,jsx,ts,tsx}', './public/index.html'],
darkMode: false, // or 'media' or 'class'
theme: {
extend: {},
},
variants: {
extend: {},
},
plugins: [],
}
```
#### Create styles directory and files
Next, let's create a `styles` folder and a new `tailwind.scss` file inside of it. Move the `index.css` file that was generated when creating your React app into the `styles` directory and rename it to `index.scss`. In the `tailwind.scss` file, import in Tailwind's `base`, `components`, and `utitlities` styles, replacing all the original file contents.
```css
// src/tailwind.scss
@import "tailwindcss/base";
/* Start purging... */
@import "tailwindcss/components";
/* Stop purging. */
/* Start purging... */
@import "tailwindcss/utilities";
/* Stop purging. */
/* Custom utilities */
```
Next, you'll need to import the CSS file in your `/src/index.js`
```diff
import React from 'react';
import ReactDOM from 'react-dom';
+ import './styles/index.scss';
+ import './styles/tailwind.scss';
import App from './App';
import reportWebVitals from './reportWebVitals';
ReactDOM.render(
<React.StrictMode>
<App />
</React.StrictMode>,
document.getElementById('root')
);
```
The `index.scss` will be empty for now until component styles are imported in when you start creating components in the next lesson.
#### Run your development environment
Run the below command to start up your development environment:
```bash
npm run start
# OR
yarn start
```
There might be a caveat with downgrading your PostCSS version if you run into this error when your development environment starts.
```
Error: PostCSS plugin tailwindcss requires PostCSS 8.
```
If this is the case, follow the rest of the commands below to install PostCSS 7 and restart your local development environment after. To read more about Tailwind's compatibility build [here](https://tailwindcss.com/docs/installation#post-css-7-compatibility-build).
```bash
npm uninstall tailwindcss postcss autoprefixer
npm install -D tailwindcss@npm:@tailwindcss/postcss7-compat @tailwindcss/postcss7-compat postcss@^7 autoprefixer@^9
# OR
yarn remove tailwindcss postcss autoprefixer
yarn add -D tailwindcss@npm:@tailwindcss/postcss7-compat @tailwindcss/postcss7-compat postcss@^7 autoprefixer@^9
```
Once the error clears out, let's go back to `App.js` and replace the markup with:
```jsx
function App() {
return (
<div className="App">
<header className="App-header">
<img src={logo} className="App-logo" alt="logo" />
<p>
Frontend Foxes School
</p>
<a
className="App-link"
href="https://reactjs.org"
target="_blank"
rel="noopener noreferrer"
>
Learn how to build your own portfolio
</a>
</header>
</div>
);
}
export default App;
```
In localhost:3000, you should be able to see the compiled and hotreloaded changes reflected in your browser!
## Next
In the next lesson, we will be diving into creating React components!
---
## Credits
Written with ♥️ by [Jaeriah Tay](https://www.twitter.com/jaeriahtay)

@ -0,0 +1,237 @@
# Build out your site: Components, State, Props, JSX & Hooks
### Introduction
We will be continuing on from the previous lesson where you set up your React project with Tailwind, a CSS utility-first library. This lesson will go over the core fundamentals of what makes React a modern library to build user interfaces using small composable pieces of code. We will be using 'components' to isolate blocks and elements of the project according to React's best code practice. What makes React a library instead of a framework is because of its flexibility, efficiency, and declarativeness and as developers we have the freedom to make architectural decisions that makes sense for our projects.
In this section, we'll start by laying out the foundations to create your very own customizable single page application portfolio in React. We will build out composable components, use React Hooks, use state and props to pass data around, and learn how to use JSX to render our templates in our portfolio application.
## JSX: JavaScript and XML
To refresh our memory in the last lesson, we edited the paragraph and anchor elements in a syntax that looks exactly like HTML. In fact, it is not HTML and is actually a markup language called JSX, which stands for JavaScript XML. Using JSX, we can write code that looks like HTML in our JavaScript files. JSX is not mandatory or neccessary to write markup in your React application but it is definitely a more convenient and accessible way. Consider the difference below in using the `createElement` method, which is what JSX is under the hood. `React.createElement` creates one instance of a component by passing the first argument a string of the element tag, the second argument as an empty object to pass in optional attributes, and lastly the inner tags you would like to render.
Using `React.createElement`:
```jsx
const Hero = () => {
return React.createElement(
"div",
{},
React.createElement("h1", {}, "My portfolio")
);
};
```
Using JSX:
```jsx
const Hero = () => {
return (
<div className="hero">
<h1>My portfolio</h1>
</div>
);
}
```
Essentially, JSX translate the HTML tags into `React.createElement` calls. Note that `className` attribute key is used instead of `class`, as `class` is a reserved keyword in JavaScript. JavaScript expressions can also be written inside JSX. For instance, the code below shows a variable or prop passed in. We will dive more into props later in the lesson. In the JSX, you would then output the prop's value inside curly braces. When the component renders, the name's value will output onto the DOM.
```jsx
const Hero = ({ name }) => {
return (
<div className="hero">
<h1>My name is {name} and this is my portfolio!</h1>
</div>
);
}
export default Hero;
```
## Components
Components are sections of your application that you extract out into separate files so that you can make them reusable. Conceptually, components are like JavaScript functions. There are two types of components, functional components and class components. Because of the nature of React's ecosystem and how its features, recommendations, and versions are continually updated, for brevity's sake we will learn the build the project with function components. You have already seen the first component generated when we ran `create-react-app` in `App.js`. The simplest way to define a component is to write a JavaScript function. Let's start by creating our first component file called `Hero.js` inside a new directory called `components/` under the `src` folder. A function component must always return markup, which is what `React.createElement` generates.
```jsx
const Hero = () => {
return (
<div className="hero">
// ...
</div>
);
}
export default Hero;
```
As you can see, we've written our function using the arrow function concept introduced in JavaScript ES6 which works the same way as a regular function component.
## Props
We briefly touched on props in our examples above. In this section, we'll go into more details of how to use props and how to use an alternative to props if you plan on passing data around your application.
### What are props (properties)?
Props (short for properties) are plain JavaScript objects that hold data that can effect the output of the render function your application's components. Props are data that are meant to be passed around so consider that if you have a rather large application with nested components, you'll need to pass down data from the top most parent component down to the child component. Let's have a look at our 'Hero' component:
```jsx
const Hero = ({ name }) => {
return (
<div className="hero">
<h1>My name is {name} and this is my portfolio!</h1>
</div>
);
}
export default Hero;
```
The `name` prop variable is being passed down from a parent component which is our `App.js` in this case. This is currently an arbitrary data value that we haven't defined yet. But what is happening here is that `name` is a variable or 'placeholder' that when rendered will evaluate to whatever you've set the value to e.g a string containing your name.
Let's now have a look at our `App.js` with some markup edits and adding of a data layer:
```jsx
import { heroData } from './mock/data';
import Hero from './components/Hero';
function App() {
return (
<div className="App">
<Hero heroData={heroData} />
</div>
);
}
export default App;
```
We are importing in a mock data file, which we will get to creating later and defining an attribute prop called `heroData` to pass in our data also called `heroData`. The attribute can be called any arbitrary name but is a good idea to name it something that pertains to the value you're expecting. In our `Hero.js`, we'll then need to pass in the prop and render out the hero data's property such as a `name`.
```jsx
const Hero = ({ heroData }) => {
return (
<div className="hero">
<h1>My name is {heroData.name} and this is my portfolio!</h1>
</div>
);
}
export default Hero;
```
We won't be dealing with too much complex data in this course but the examples provided give some options as to how React can handle data in multiple ways depending on preference and use cases. Before we go any further with introducing another way of providing centralized data, let's create a file where we will store our portfolio data to pull from. In a real-world application, there are other ways to input and source your data from platforms such as a Content Management System or even from markdown. For this project and course, we'll be creating a mock data to pull data objects from, so let's get right to it!
### Creating a data source
First create a new directory in `src` called `mock` and a file inside of it call `data.js`. Copy in the following snippet to that file:
```jsx
// Head data
export const headData = {
title: 'Name | Developer', // e.g: 'Name | Developer'
description: 'Welcome to my portfolio', // e.g: Welcome to my website
};
// Hero data
export const heroData = {
title: 'Hi, my name is',
name: 'Name',
subtitle: 'I\'m a developer!',
cta: 'Know more',
};
// About data
export const aboutData = {
img: 'profile.jpg',
paragraphOne: '',
paragraphTwo: '',
paragraphThree: '',
resume: '', // if no resume, the button will not show up
};
// Projects data
export const projectsData = [
{
id: nanoid(),
img: 'project.jpg',
title: '',
info: '',
info2: '',
url: '',
repo: '', // if no repo, the button will not show up
},
{
id: nanoid(),
img: 'project.jpg',
title: '',
info: '',
info2: '',
url: '',
repo: '', // if no repo, the button will not show up
},
{
id: nanoid(),
img: 'project.jpg',
title: '',
info: '',
info2: '',
url: '',
repo: '', // if no repo, the button will not show up
},
];
// Contact data
export const contactData = {
cta: '',
btn: '',
email: '',
};
// Footer data
export const footerData = {
networks: [
{
id: nanoid(),
name: 'twitter',
url: '',
},
{
id: nanoid(),
name: 'codepen',
url: '',
},
{
id: nanoid(),
name: 'linkedin',
url: '',
},
{
id: nanoid(),
name: 'github',
url: '',
},
],
};
```
In this file, we've created several objects with properties and immediately exported them. For brevity's sake, each of the object points to a component in the portfolio project with mainly string properties that we will use to store our data. You can replace or fill out the key values on those properties when you start to build out more components. Note the `nanoid()` function we are calling at the `id` keys. `nanoid` is an external library we will be using to generate unique string IDs. Let's go ahead a install nano id now:
```bash
npm i nanoid
# OR
yarn add nanoid
```
Unique ID keys are necessary when rendering lists in React as the keys help React to identify which items have changed. We will go into keys and lists when we get to mapping out and rendering the lists in our components. Go to this [React documentation](https://reactjs.org/docs/lists-and-keys.html#keys) to read more about keys.
## Context and hooks
useContext
## Hooks
## Credits
Written with ♥️ by [Jaeriah Tay](https://www.twitter.com/jaeriahtay)
Loading…
Cancel
Save