- Explain what a frontend framework is and why they can be helpful in writing more complex applications.
- Explain what ReactJS is and where it fits in our applications' stack.
- Explain the component model of web development.
- Create and render React components in the browser.
- A framework is software providing generic functionality and structure that serves as foundation to build and deploy applications.
- Express is a framework that runs on the server, receiving incoming request from the client, preforming some work that you have defined, and returning some response to the client. Front-end frameworks run in the client's browser, receive input from interactions with the page, perform some work that you have defined, and make any updates necessary.
- Frameworks can help standardize code, give you additional functionality and performance, and can help get your code off the ground faster.
- There are many front end frameworks and each go about solving problems of how state is managed, updated, and represented by a view but there are many commonalities.
- There is a lot of debate over whether frontend frameworks count as frameworks at all -- some people say that they are just libraries and should be referred to as such.
React is a JavaScript library used to craft modern day UI and views for the front-end in web applications.
Selling Point: By modeling small compatible components that focus on just rendering a view, we can move business logic out of the DOM, and therefore improve our app's performance, maintainability, modularity and readability.
Please install the following Chrome extension: React Dev Tools.
The first thing most people hear about React is "Facebook uses it."
- First used by Facebook in 2011.
- Then Instagram in 2012.
- Went open source in May 2013.
- Changed licence to MIT in 2017.
React was born out of Facebook's frustration with the traditional MVC model and how..
- Re-rendering something meant re-rendering everything (or just a lot).
- That had negative implications on processing power and ultimately user experience, which at times became glitchy and laggy.
If you want to get a taste of what React is all about, here's an introduction from React.js Conf 2015. Recommend starting around the 8:35 mark and watching until 16:30.
React can be thought of as the "Views" layer.
React will work with any back-end language, but for project 3 and in our in-class examples we will be using Mongoose and Express for the models and controllers.
What is the role of a "view" in a front-end Javascript application?
The visual template the user sees, often populated with data from our models.One comment made about React when it was first open sourced was "Rethinking established best practices" which kind of became the React motto. In React, we want to move away from template pages, away from separating code based purely on file type, and more towards a component-based separation of concerns. Templates vs Components
When taking a look at Facebook, you could think of each status post as a mini-component in React. And a list of those updates, is a component that contains several of those mini-components. You could take that one step further and think of the Facebook app, as one giant component with several components within it. (Things like the list of status updates, the friends list, the header, etc...)
Imagine you worked at Facebook when they wanted to shift from using likes to reactions. Using traditional JavaScript, HTML, and CSS the shift would make you have to change your code in a bunch of places. Component based architecture allows us to maintain our code more easily.
Notice the structure of how the various components are nested.
- TubeTracker
- Network
- Line
- Predictions
- DepartureBoard
- Trains
TubeTracker contains the application Network displays each line on the network Line displays the stations on a line Predictions controls the state of the departure board DepartureBoard displays the current station and platforms Trains displays the trains due to arrive at a platform
A React component is built to expect an input and render a UI with it. More importantly, a well-structured component only receives data specific to its purpose.
This is because React follows a more functional approach to programming. For React components under this approach, the same input will always produce the same output.
Best practice is that React components follow the F.I.R.S.T. guidelines
Components should do one thing and do it well.
Components should increase cohesion and reduce coupling. Behavior in one component should not impact the behavior of another. In other words, components should not rely on one another.
But they should compliment one another.
Components should be written in a way that reduces the duplication of code.
Ideally, components should be short and condensed.
Because the same input will always produce the same output, components are easily unit testable.
If you're interested, Jest is a popular testing library for React.
10 minutes exercise. 5 minutes review.
- Break into groups of three and take a look at Facebook, Craigslist, Ebay, or a website of your choice. Identify the visual "components" the website is comprised of. Use markers to draw these out on the wall.
As you're drawing this out, think about the following questions...
- Where do you see "nested components"? Where do you not?
- Are there any components that share the same structure?
- Of these similar components, what is different about them?
In order to create a new project and to get our development environment setup, we are going to use the Terminal command create-react-app
. It will create a new folder in your current directory for the in-class application.
create-react-app
is an NPM package also built by Facebook that writes our build dependencies for us so that we can do less configuration. It allows us to use React, JSX, and ES6. It also allows us to import our CSS, it autoprefixes our CSS so that we don't have to worry about cross browser compatibility, it gives us a dev server to run, and it enables hot reloading which updates the code in our browser without us refreshing the page.
It uses Webpack which is a build tool that enables many of the features listed above. It also includes Babel which transpiles our JavaScript from ES6 to be compatible with older browsers. It also includes Autoprefixer for CSS compatibility, ESLint for linting, and Jest for testing.
You can also set up all this yourself, but for now create-react-app
allows us to worry more about our code and less about configuration.
$ npm i -g create-react-app
$ create-react-app blog-app
$ cd blog-app
$ code .
$ npm run start
Here you will begin setting up a blog app that you will continue working on during this lesson's exercises. For demonstration purposes, We will be creating a simple "hello world" app.
After running $ npm run start
, we can view the app at http://localhost:3000
create-react-app
provides us with all the necessary tools and configuration necessary to start writing React. npm run start
refers to an included script that starts up the development server.
Along with installing the necessary dependencies, it creates an initial app skeleton that looks like this...
├──README.md
├── favicon.ico
├── index.html
├── node_modules
├── package.json
└── src
├── App.css
├── App.js
├── index.css
├── index.js
└── logo.svg
Most of the important files, which are primarily the ones where we will be working today, are in the /src
directory.
Take some time and look at what's been generated. Specifically look in App.js
and index.js
The basic unit you'll be working with in ReactJS is a component.
- Components can be thought of as functional elements that take in data and as a result, produce a dynamic UI.
Throughout class we have separated HTML, CSS and Javascript.
- With components, the lines between those three become a bit blurry.
- Instead, we organize our web apps according to small, reusable components that define their own content, presentation and behavior.
What does a component look like? Let's start with a simple "Hello World" example...
To start, in our /src/App.js
file, let's remove the contents and in its place add this component definition...
// bring in React and Component instance from React
import React, {Component} from 'react'
// define our Hello component
class Hello extends Component {
// what should the component render
render () {
// Make sure to return some UI
return (
<h1>Hello World!</h1>
)
}
}
export default Hello
Let's break down the things we see here...
This is the component we're creating. In this example, we are creating a "Hello" component.
This is the React library class we inherit from to create our component definition.
Every component has, at minimum, a render method. It generates a Virtual DOM node that will be added to the actual DOM.
- Looks just like a regular ol' DOM node, but it's not yet attached to the DOM.
This exposes the Hello class to other files which import from the App.js file. The default
keyword means that any import that's name doesn't match a named export will automatically revert to this. Only one default is allowed per file.
Hey you got your html in my javascript!
You got your javascript in my html!
Let's talk about the value that the render method returns. It looks an awful lot like an HTML heading, but it's not. We often write out React components in JSX.
JSX is a language that compiles to Javascipt that allows us to write code that strongly resembles HTML. It is eventually compiled to lightweight JavaScript objects.
Your Hello component's render method:
- Currently returns JSX, not HTML. The JSX creates a heading with 'Hello World!'.
- Your component reads this and renders a "Hello World!" heading.
React can be written without JSX. If you want to learn more, check out this blog post.
You may have noticed that our src/index.js
code mentions ReactDOM. ReactDOM doesn't refer to the same DOM we know. Instead, it refers to a Virtual DOM. The Virtual DOM is a key piece of how React works.
The Virtual DOM is a Javascript representation of the actual DOM. The virtual DOM is a staging area for changes that will eventually be implemented.
- Because of that, React can keep track of changes in the actual DOM by comparing different instances of the Virtual DOM.
- React then isolates the changes between old and new instances of the Virtual DOM and then only updates the actual DOM with the necessary changes.
- By only making the "necessary changes," as opposed to re-rendering an entire view altogether, we save up on processing power.
- This is not unlike Git, with which you compare the difference -- or
diff
-- between two commits.
If you're interested in learning more about the Virtual DOM, check this video out.
So we've created the template for our component. Now, let's use /src/index.js
to load in our new component and render it on the DOM...
import React from 'react'
import ReactDOM from 'react-dom'
import Hello from './App.js'
ReactDOM.render(
<Hello />,
document.getElementById('root')
)
In place of
ReactDOM.render
some tutorials will use React.renderComponent, which has been phased out. The change is outlined here.
ReactDOM.render
takes the Virtual DOM node created by extends Component
and adds it to the actual DOM. It takes two arguments...
- The component.
- The DOM element we want to append it to.
NOTE: Whenever you use a self-closing tag in JSX, you MUST end it with a
/
like<Hello />
in the above example.
Our Hello
component isn't too helpful. Let's make it more interesting.
- Rather than simply display "Hello world", let's display a greeting to the user.
- So the question is, how do we feed a name to our
Hello
component without hardcoding it into our render method?
First, we pass in data wherever we are rendering our component, in this case in src/index.js
...
import React from 'react'
import ReactDOM from 'react-dom'
import Hello from './App.js'
ReactDOM.render(
<Hello name={"Nick"} />,
document.getElementById('root')
)
Then in our component definition, we have a reference to that data via as a property on the props
object...
class Hello extends Component {
render () {
return (
<h1>Hello {this.props.name}</h1>
)
}
}
In the above example, we replaced "world" with {this.props.name}
.
Properties! Every component has .props
- Properties are immutable. That is, they cannot be changed while your program is running.
- We define properties in development and pass them in as attributes to the JSX element in our
.render
method.
First we can pass multiple properties to our component when its rendered in src/index.js
..
import React from 'react';
import ReactDOM from 'react-dom'
import Hello from './App.js'
ReactDOM.render(
<Hello name={"Nick"} age={24} />,
document.getElementById('root')
)
Then in our component definition we have access to both values...
class Hello extends Component {
render () {
return (
<div>
<h1>Hello {this.props.name}</h1>
<p>You are {this.props.age} years old</p>
</div>
)
}
}
NOTE: The return statement in
render
can only return one DOM element. You can, however, place multiple elements within a parent DOM element, like we do in the previous example with<div>
.
20 min to work, 5 min review
Let's have some practice creating a React component from scratch. How about a blog post?
- Create a
post
object literal insrc/index.js
aboveReactDOM.render()
that has the below properties.title
author
body
comments
(array of strings)
- Render these properties using a Post component.
- The composition of your Post is up to you.
If you finish early, try experimenting with CSS (Make Sure you use className
instead of class
in JSX
!)
It would be a pain to have to explicitly define every comment inside of <Post />
, especially if each comment itself had multiple properties.
- This problem is a tell tale sign that our separation of concerns is being stretched, and it's time to break things into a new component.
We can nest a Comment component within a Post component.
- We create these comments the same way we did with posts:
extends Component
andrender
- Then we can reference a comment using
<Comment />
inside of Post's render method.
Let's create a new file for our Comment component, src/Comment.js
...
import React, {Component} from 'react'
class Comment extends Component {
render () {
return (
<div>
<p>{this.props.message}</p>
</div>
)
}
}
export default Comment
Then in src/App.js
, we need to load in our Comment
component and render it inside of our Post
component...
import React, { Component } from 'react';
// Load in Comment component
import Comment from './Comment.js'
class Post extends Component {
render() {
return (
<div>
<h1>{this.props.title}</h1>
<p>By {this.props.author}</p>
<div>
<p>{this.props.body}</p>
</div>
<h3>Comments:</h3>
// Render Comment component, passing in data
<Comment message={this.props.comments[0]} />
</div>
);
}
}
export default Post;
Note: We could put all of our code in one file, but it's considered a good practice to break components out into different files to help practice separation of concerns. The only downside is we have to be extra conscious of remembering to export / import each component to where it's rendered.
The above code works, but we'd have to hard-code all of our Comments
. This is not very dry and our code will not dynamically change. The best way to handle this is to set a variable equal to all of the <Comments />
for this post. We can do this using .map
in Post's
render
method.
We can use .map
in Post's
render
method to avoid having to hard-code all of our Comments
class Post extends Component {
render() {
let comments = this.props.comments.map((comment, index) => (
<Comment message={comment} key={index}/>
))
return(
<div className='post-page'>
<h1>{this.props.title}</h1>
<h2>By {this.props.author}</h2>
<p>{this.props.body}</p>
<h3>Comments</h3>
{comments}
</div>
)
}
}
- Why do we use components in React?
- What is the Virtual DOM?
- What is JSX?
- What features does
create-react-app
give us?