Day 6: React

Tuesday, May 23, 2017

Lecture Videos

Morning:

Afternoon:

Topics

React

  • Using map with components
  • Stateless Functional Components
  • Conditional rendering

JavaScript

  • Named and default exports
  • Named and default imports
  • Property initializers
  • Spread operator
  • Destructuring assignment

Package Managers

  • NPM - Node Package Manager
  • Yarn - Facebook’s version of npm

CSS Specifity

Examples

React

Using map with Components

See this example live on CodePen →

Person.js



class Person extends React.Component {
  render() {
    return (
      <li>Hello, {this.props.person.name}!</li>
    )
  }
}

export default Person


PersonList.js



import Person from './Person'

class PersonList extends React.Component {
  render() {
    const people = [
      { name: 'Seth', hair: 'blonde' },
      { name: 'Nichole', hair: 'long' },
      { name: 'Davey', hair: 'long gone' }
    ]
    return (
      <div>
        <h2>People</h2>
        {
          people.map((person => <Person person={person} />))
        }
      </div>
    )
  }
}

export default PersonList


Stateless Functional Components

Not every React Component needs to have state. Many simply render a bit of props and UI. For such components, we don’t need to instantiate a whole class that inherits from React.Component, we can simply write a function that accepts props as an argument and returns the markup we need.

For instance, in the previous example, the Person component can easily be re-written as a Stateless Functional Component.



function Person (props) {
  return (
    <li>Hello, {props.person.name}!</li>
  )
}

// Or...

const Person = (props) => <li>Hello, {props.person.name}!</li>


Conditional Rendering

There are many instances where you may want to render different UI depending on the state of the application. One example would be a button that shows “Log in” or “Log out”, depending on whether there is a currently logged-in user.

Since React is just JavaScript, we can conditionally render using if/else statements, or we also learned about the ternary operator.



const condition = true

if (condition) {
  console.log('true!')
} else {
  console.log('false!')
}
// => 'true!'

condition ? console.log('true!') : console.log('false!')
// => 'true!'


An example in React:



function UserButton (props) {
  return (
    {props.loggedInUser ? <button>Log out</button> : <button>Log in</button>}
  )
}


JavaScript (ES6+)

Named and default exports and imports

Prior to ES6, there were many competing ways to export and import JavaScript modules. The most common were CommonJS and AMD. Luckily ES6 defined a specification for standardizing module export and import.

There are two types of exports from any JS file - named and default. The important thing to remember is that there can only be one default export per module, but there can be as many named exports as you want.

myModule.js



export const myNumber = 8

export function sayHi () {
  console.log('hello')
}

export default class MyClass {
  add (a, b) {
    return a + b
  }
}


The main difference is how they are imported. Default exports get the most concise syntax:



import MyClass from 'myModule'

const classInstance = new MyClass()
classInstance.add(1, 2) // => 3


Default import naming

Since there can be only one default export per module, the name by which you import the default export is not important - you can name it whatever you want. For instance, instead of importing as MyClass, we could have said import LuftBallons from 'myModule', and it would have worked just fine. To read more about default and named exports, click here.

Named exports get a slightly more verbose syntax for importing, and the names are important (otherwise it can’t determine what you want to import).



import { myNumber, sayHi } from 'myModule'

console.log(myNumber) // => 8

sayHi() // => 'hello'


If you need to import a named export under a different name—if, for example, you have another import or local variable with the same name—you can specifiy a different name using as.



import { myNumber as num, sayHi as yo } from 'myModule'

console.log(num) // => 8

yo() // => 'hello'


You can also combine default and named imports in the same line.



import MyClass, { myNumber, sayHi } from 'myModule'


Property initializers

From the proposal:

“Class instance fields” describe properties intended to exist on instances of a class (and may optionally include initializer expressions for said properties).

We can take advantage of this in React.

Read more: Using ES7 property initializers in React

We can use a property initializer to set the initial value of state without writing a constructor:



class Song extends React.Component {
  state = {
    versesRemaining: 5,
  }
}


We can even set default props and use those in the initial state:



class Song extends React.Component {
  static defaultProps = {
    autoPlay: false,
    verseCount: 10,
  }
  state = {
    versesRemaining: this.props.verseCount,
  }
}


Subject to minor changes

Property initializers are a Stage 2 proposal for ECMAScript, meaning that it’s still a draft and is subject to minor changes before becoming standardized. Facebook itself is already using these techniques in production, however.

Spread operator

The spread operator was added in ES6 to allow an expression to be expanded in places where multiple arguments (for function calls) or multiple elements (for array literals) or multiple variables (for destructuring assignment) are expected.



function myFunc (x, y, z) {
  console.log(x)
  console.log(y)
  console.log(z)
}
const args = [1, 2, 3]

myFunc(...args) // the spread '...args' applies the items in args to the three arguments in myFunc
// => 1
// => 2
// => 3


It is also an easy way to make copies of iterable objects



const ary = [1, 2, 3]
const aryCopy = [...ary] // makes a copy of ary


If you are in a project using Babel (like a React project created with create-react-app), you can also use the object-rest-spread-transform to apply this same method to objects.



this.state = {'a': true, party: 'hard'}
const stateCopy = {...this.state} // makes a copy of this.state


Destructuring assignment

Destructuring assignment syntax is a JavaScript expression that makes it possible to unpack values from arrays, or properties from objects, into distinct variables.



const myObj = {
  a: true,
  b: 'Destructuring!'
}

let { a, b } = myObj

console.log(a) // => true
console.log(b) // => 'Destructuring!'


Package Managers

Node Package Manager (npm)

Node Package Manager hosts almost half a million packages of free, reusable JavaScript code and is the largest software registry in the world. It allows you to easily add any module to your project, and it will install the requested package, as well as any required dependencies of that package.

user@localhost ~
 
npm install react

Yarn

Yarn is Facebook’s version of npm, designed to improve performance and resolve several important issues. The key differences are:

  • Deterministic installation - packages will always install in the same order on every machine
  • yarn.lock - this lockfile locks dependency versions for consistency and security
  • Local cache of downloaded packages - faster and can still work with no internet connection after initial installation
  • Parallel installation - Dependency installation can happen in parallel, greatly increasing speed

To install yarn (npm was already installed as part of setup instructions), type the following command:

user@localhost ~
 
brew install yarn

Once installed, you can use yarn with following commands:

user@localhost ~
 
yarn
# installs all packages and dependencies listed in your project's package.json

yarn add {package_name}
# installs a new package and adds it to package.json

yarn start
# starts your local development web server (in project from create-react-app)

Projects

Homework

Add the Add Thing button, including the corresponding CSS.

Bonus Credit

Make that button work!

Super Mega Bonus Credit

Stop hard-coding things altogether. Use only the things that were added via the Add Thing button.

Super Mega Bonus Credit Hyper Fighting

Make the remove button work.