Skip to content

ga-wdi-lessons/react-intro

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

71 Commits
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Intro to React.js


react-logo


Learning Objectives

  • 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.
  • Pass in data to a React component via props.
  • Nest React components.
  • Modify the state of a React component through events.

Framing (5 minutes / 0:05)

What is ReactJS?

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.

Some History

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.

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's all about, here's an introduction from React.js Conf 2015. Recommend starting around the 8:35 mark and watching until 16:30.

React in MVC

React can be thought of as the "Views" layer.

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.

React can be used agnostically throughout your stack. It's role is just to use data to render a UI. This means that React can also co-exist with other Javascript frameworks. Let the other frameworks handle the models and controllers, and have React sort out the views.


Initial Setup (20 minutes / 0:25)

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.

$ npm i -g create-react-app
$ create-react-app blog-app
$ cd blog-app
$ atom .
$ 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, I 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 such as React, ReactDom, Babel and Webpack, 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.


Stop / Catch Up / Investigate

Take some time and look at what's been generated. Specifically look in App.js and index.js


Components

One of the snarky comments made about React when it was first open sourced was. "Rethinking established best practices". Traditionally we're used to a more MVC approach for separation of concerns. In React, we want to move towards more of a component-based separation of concerns. 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...)

You Do: Identifying Components (10 minutes / 0:35)

5 minutes exercise. 5 minutes review.

Break into pairs and take a look at CraigsList. Identify the visual "components" the website is comprised of. We suggest using markers to draw these out on your table! So something like this...

Component diagram

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?

I Do: Hello World - A Very Basic Component (10 minutes / 0:45)

No need to follow along with this Hello World example. You will have the chance to implement this yourself when you get to the first Blog exercise.

The basic unit you'll be working with in ReactJS is a component.

  • It sounds like a simple word, but using "components" is a pretty different way of approaching web development.

  • Components can be thought of as functional elements that takes 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 recap what's going on.

What's that HTML doing in my Javascript?

Often times we 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.
  • React then uses these objects to build out a "Virtual DOM" -- more on that in just a bit.

React can be written without JSX. If you want to learn more, check out this blog post.

Let's break down the things we see here...

class Hello

This is the component we're creating. In this example, we are creating a "Hello" component.

extends Component

This is the React library class we inherit from to create our component definition.

render()

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.
export default Hello

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.

Virtual DOM? How is that different from the usual DOM?

The Virtual DOM is a Javascript representation of the actual DOM.

  • 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.

Virtual DOM Diagram

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...

  1. The component.
  2. The DOM element we want to append it to.

What is <Hello /> written in? JSX.

  • Similar to XML.
  • When we say <Hello />, in plain Javascript we are actually saying React.DOM.div( null, "Hello world.")
    • Basically, a string of React methods that create a virtual DOM node.

NOTE: Whenever you use a self-closing tag in JSX, you MUST end it with a / like <Hello /> in the above example.


Hello World: A Little Dynamic (10 minutes / 0:55)

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}.

What are .props?

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>.


Break (10 minutes / 1:05)


You Do: A Blog Post (25 minutes / 1:30)

Let's have some practice creating a React component from scratch. How about a blog post?

  • Create a post object literal in src/index.js that has the below properties.
    1. title
    2. author
    3. body
    4. comments (array of strings)
  • Render these properties using a Post component.
  • The HTML (or more accurately, JSX) composition of your Post is up to you.

Nested Components (5 minutes / 1:35)

Q: What problems did you encounter when trying to add multiple comments to your Post?

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 Comment components within a Post component.

  • We create these comments the same way we did with posts: extends Component and .render
  • 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.body}</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 body={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.


You Do: Add Nested Comments To Blog (15 minutes / 1:50)

Amend your Post's render method to include reference to a variable, comments, that is equal to the return value of generating multiple <Comment /> elements. Make sure to pass in the comment body as an argument to each Comment component. Then render the comments somewhere inside the UI for a Post.

NOTE: You can use .map in Post's render method to avoid having to hard-code all your Comment's. Read more about it here and here.

HINT I: You should only have to return one <Comment /> inside of .map.

HINT II: Each comment needs a key attribute to keep track of data passed as props. The key should be a unique identifier for each child component

HINT III: Remember that whenever you write vanilla Javascript inside of JSX, you need to surround it with single brackets ({}).


Break (10 minutes / 2:00)


State (10 minutes / 2:10)

So we know about React properties, and how they relate to our component's data.

  • The thing is, props represent data that will be the same every time our component is rendered. What about data in our application that may change depending on user action?
  • That's where state comes in..

Values stored in a component's state are mutable attributes.

  • Like properties, we can access state values using this.state.val
  • Setting up and modifying state is not as straightforward as properties. It involves explicitly declaring the mutation, and then defining methods to define how to update our state...

Lets implement state in our earlier Hello example by incorporating a counter into our greeting.

class Hello extends Component {
  // when our component is initialized,
  // our constructor function is called
  constructor () {
    // make call to parent class' (Component) constructor
    super()
    // define an initial state
    this.state = {
      counter: 0 // initialize this.state.counter to be 0
    }
  }
  render () {
    return (
      <div>
        <h1>Hello {this.props.name}</h1>
        <p>You are {this.props.age} years old</p>
        <p>The initial count is {this.state.counter}
        </p>
      </div>
    )
  }
}

Ok, we set an initial state. But how do we go about changing it?

  • We need to set up some sort of trigger event to change our counter.

Take a look at how this event is implemented. We use an attribute called onClick to define what happens when we click this particular button. As its value, we're passing in an anonymous function that invokes handleClick, a function defined on this component.

class Hello extends Component {
  constructor () {
    super()
    this.state = {
      counter: 0
    }
  }
  handleClick (e) {
    // setState is inherited from the Component class
    this.setState({
      counter: this.state.counter + 1
    })
  }
  render () {
    // can only return one top-level element
    return (
      <div>
        <h1>Hello {this.props.name}</h1>
        <p>You are {this.props.age} years old</p>
        <p>The initial count is {this.state.counter}
        </p>
        <button onClick={(e) => this.handleClick(e)}>click me!</button>
      </div>
    )
  }
}

Whenever we run .setState, our component mimics a diff against the current DOM, and compares the Virtual DOM node with the updated state to the current DOM.

  • Only replaces the current DOM with parts that have changed.

Exercise: Implement State (20 minutes / 2:30)

Let's implement state in our Blog by making body a mutable value.

  1. Initialize a state using a constructor() method for our Post to set a initial state. It should create a state value called body. Set it to the body of your hard-coded post.
  2. Modify Post's render method so that body comes from state, not props.
  3. Create a handleClick method inside Post that updates body based on a user input.
  • You should use setState somewhere in this method.
  • How can you get a user input? Keep it simple and start with prompt.
  1. Add a button to Post's render method that triggers handleClick.

Bonus I

Use a form to take in user input.

  • The post body should be updated using a method that is triggered by onSubmit.
  • One option is to keep track of what the new input is going to be by triggering a method using onChange on the <input>
  • Another option is to pass an event object to the onSubmit method and traverse the DOM from e.target to find the <input> value.

NOTE: You're starting to mock Angular's two-way data binding!


Closing

What's Next?


Additional Reading