diff --git a/images/antsGoMarching.png b/images/antsGoMarching.png new file mode 100644 index 0000000..f93eade Binary files /dev/null and b/images/antsGoMarching.png differ diff --git a/images/full_component_lifecycle.png b/images/full_component_lifecycle.png new file mode 100644 index 0000000..1f1cbfd Binary files /dev/null and b/images/full_component_lifecycle.png differ diff --git a/images/full_reactjs_component_lifecycle.png b/images/full_reactjs_component_lifecycle.png new file mode 100644 index 0000000..0b88a86 Binary files /dev/null and b/images/full_reactjs_component_lifecycle.png differ diff --git a/images/react_component_lifecycle.jpg b/images/react_component_lifecycle.jpg new file mode 100644 index 0000000..2d13bf1 Binary files /dev/null and b/images/react_component_lifecycle.jpg differ diff --git a/images/react_lifecycle b/images/react_lifecycle new file mode 100644 index 0000000..5301f1c Binary files /dev/null and b/images/react_lifecycle differ diff --git a/images/react_lifecycle.png b/images/react_lifecycle.png new file mode 100644 index 0000000..5301f1c Binary files /dev/null and b/images/react_lifecycle.png differ diff --git a/images/react_simple_component_lifecycle.png b/images/react_simple_component_lifecycle.png new file mode 100644 index 0000000..b386c43 Binary files /dev/null and b/images/react_simple_component_lifecycle.png differ diff --git a/images/reactjs_component_lifecycle.html b/images/reactjs_component_lifecycle.html new file mode 100644 index 0000000..e318211 --- /dev/null +++ b/images/reactjs_component_lifecycle.html @@ -0,0 +1,19 @@ + Google Image Result for http://image.slidesharecdn.com/ypyfe-150523113716-lva1-app6891/95/react-16-638.jpg?cb=1432381135
\ No newline at end of file diff --git a/images/reactjs_component_lifecycle.jpeg b/images/reactjs_component_lifecycle.jpeg new file mode 100644 index 0000000..58a7df6 Binary files /dev/null and b/images/reactjs_component_lifecycle.jpeg differ diff --git a/images/what-is-webpack.png b/images/what-is-webpack.png new file mode 100644 index 0000000..519ed22 Binary files /dev/null and b/images/what-is-webpack.png differ diff --git a/lesson 12 - ES2015.md b/lesson 12 - ES2015.md new file mode 100644 index 0000000..d8a3e88 --- /dev/null +++ b/lesson 12 - ES2015.md @@ -0,0 +1,1017 @@ +# ES6 A.K.A ES2015 + +## Recap & Intro +- Last week we learned about application setup and configuration +- We also discussed the use of loaders in your webpack config +- Tonight we'll be discussing ES2015, the newest specification of JavaScript + + +## Agenda + +- Tonight we'll cover the changes that ES2015 offers +- The objective is for you become comfortable with the new features and syntax +- We'll also cover how to include ES2015 in your current projects + + + +## What is ES2015 + +ES2015 (formerly known as ES6) is the biggest change to JavaScript to date. It offers many advantages over the current ES5 spec. While this may sound intimidating, ES6 is incredibly easy to pick up if you have a solid understanding of the core principles of JavaScript. + +After learning a bit about ES2015 tonight, you'll be able to start using it immidiately. + +Though ES2015 has officially been released, the features have yet to be fully implemented in current browsers, but have no fear, with a little bit of webpack magic you can write ES2015 code and have it compile/transpile into ES5. + + +## Template Literals + +What are template literals? + +According to [Mozilla](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals): +>Template literals are string literals allowing embedded expressions. You can use multi-line strings and string interpolation features with them. They were called "template strings" in prior editions of the ES2015 / ES6 specification. + + +- Template strings are encolsed by the back-tick( ` ) character +- instead of double(`"`) or single(`'`) quotes + +```javascript +console.log(`Hello! I'm a string template`) +// Hello! I'm a string template +``` +- String templates also support multi-line strings with ease + +##### *the old-fashioned way* + +```javascript +console.log("string text line 1\n"+ +"string text line 2"); +// "string text line 1 +// string text line 2" +``` +##### *the ES2015 way* + +```javascript +console.log(`string text line 1 +string text line 2`); +// "string text line 1 +// string text line 2" +``` + +#### String Interpolation +String Literals also allow interpolation! That's right! no more concatenation of variables! + +As you know (from experience) the only way to add variables to a string is by using concatenation with the `+` operator + +##### *the old-fashioned way* + +```javascript +var name = "Shane"; +var day = "Tuesday"; + +console.log("Hello "+ name + ", I hope you have a great " + day + "!"); +``` +While this works, ES2015 allows you to wrap your variables with `${}`. This will take care of utlizing the value that your variable is pointing to. + +##### **the ES2015 way** + +```javascript +var name = "Shane"; +var day = "Tuesday"; + +console.log(`Hello ${name}, I hope you have a great ${day}!`) +``` + +As you can imagine this also works great with objects! + +```javascript +var day = "Tuesday"; +var instructor = { + name: "Shane", + lesson: "ES 2015" +} + +console.log(`Hello ${instructor.name}, I hope the ${instructor.lesson} class goes well on ${day}!`); +``` + +And if you're wondering about functions, that works too! + +```javascript +var instructor = { + name: "Shane", + lesson: "ES 2015", + greet: function(){ + return `Hi! I'm ${this.name} and tonight we'll be discussing ${this.lesson}!`; + } +} + +console.log(instructor.greet()); +``` + +## Exercise + +go to [ES6Katas](http://tddbin.com/#?kata=es6/language/template-strings/basics) and pass the first 2 sets of tests + +## let & const + +As you've been reading more about JavaScript you may have noticed the keywords `let` and `const` being used in code snippets. This new addition to the language is both simple and powerful. + +### let + +In it's most basic form, `let` is a sibling of `var`. However there is a difference. + +- `var` creates a variable scoped to it's parent function (or in the global scope) +- `let` scopes the variable to it's nearest block, (`if` statements, `for` loops, etc) + +This concept is known as **block scoping**. + +##### using `var` +```javascript +function foo() { + + let x = true; + if (x) { + var usingVar = "I'm using the var keyword"; + } + console.log( usingVar ); +} + +foo(); +// I'm using the var keyword +``` +In the above example, *usingVar* is hoisted to the top of the function, thus being made available throughout the function. + +##### using `let` +```javascript +function foo() { + let x = true; + if (x) { + let usingLet = "I'm using the let keyword"; + } + console.log( usingLet ); +} + +foo(); +// usingLet is not defined +``` +In the above example, *usingLet* is hoisted to the top of the `if` block, thus making it unavailable to the outer function's scope. + +In summary, using `let` presents many benefits, including: + +- tighter control over your variables in regards to: + - lexical scope + - closures + - hoisting +- less errors at run-time +- easier debugging + +### const + +The `const` declaration creates a *constant*. Which is essentially a **read-only** reference to the value. + +This means that once a constant is declared, it cannot be re-assigned or re-declared. + +```javascript +const instructors = ["Assaf", "Shane"] +instructors = ["Lee", "Mariel"] + +// TypeError +``` +A common misconception is that `const` is immutable. This is not entirely true. If the reference value of `const` is a complex object (ie: function, array, object), the *contents can be modified*. + +```javascript +const instructors = ["Assaf", "Shane"]; +instructors.push("Lee", "Mariel"); + +console.log(instructors) +// ["Assaf","Shane","Lee","Mariel"] +``` + +A couple of other notes on `const`: + +- variables declared with `const` can be upper or lower-case +- `const` follows the same **block scope** principles as **let** + +The use of `const` and `let` gives you more control over your code and makes it much more readable for other developers. + +## Default Parameters + +A welcome change in ES2015 is **default paramaters**. + +This feature allows you to pass default arguments to your functions. Before we dive into the syntax, let's look at the ES5 work-around + +##### *the old-fashioned way* +```javascript +function hello(name) { + name = name || 'Mystery Person'; + + console.log('Hello ' + name + "!"); +} + +hello("Bobby"); +// Hello Bobby! + +hello(); +// Hello Mystery Person! +``` +While this is a very clever work-around, it can backfire when dealing with booleans and numbers. + +ES2015 offers a much more reliable solution + +##### *the ES2015 way* +```javascript +function hello(name = "Mystery Person"){ + console.log(`Hello ${name}!`); +} + +hello("Bobby"); +// Hello Bobby! + +hello(); +// Hello Mystery Person! +``` + +Multiple default parameters can be added and mixed with regular parameters. However, keep in mind that **parameters without *default's* will initially recieve the value of undefined** (like normal). + +```javascript +function hello(day, name = "Mystery Person"){ + console.log(`Hello ${name}! have a great ${day}`); +} + +hello(); +// Hello Mystery Person! have a great undefined +``` +## Exercise + +- Complete challenge #57 (Default paramaters) at [ES6Katas](http://tddbin.com/?772#?kata=es6/language/default-parameters/basics) + +## Rest & Spread + +### Rest + +The **rest parameter** lets you pass an indefinite number of arguments as an array. + +Rest parameters are invoked using the `...` syntax + +This is similar to the **arguments** object that we learned about way back in class #3. However, **rest paramaters** offer significant advantages. + +##### the old fashioned way +```javascript +function add() { + console.log("arguments object:", arguments); + + var numbers = Array.prototype.slice.call(arguments), + + var sum = 0; + + numbers.forEach(function (number) { + sum += number; + }); + return sum; +} + +console.log(add(1,2,3,4,5,6,7,8)); +// arguments object: {"0":1,"1":2,"2":3,"3":4,"4":5,"5":6,"6":7,"7":8} +// 36 +``` + +In the above example, we had to convert the **arguments** object into an array, because it's not an *actual array* + +**Rest parameters** on the other hand, provides an actual array
*meaning methods like `sort`, `map`, `forEach` and `pop` can be applied on it directly*. + +##### the ES2015 way +```javascript +function add(...numbers) { + console.log("rest parameters:", numbers); + + let sum = 0; + + numbers.forEach(function (number) { + sum += number; + }); + return sum; +} + + console.log(add(1,2,3,4,5,6,7,8)); +// rest parameters: [1,2,3,4,5,6,7,8] +// 36 +``` + +As you can see, this new syntax is much more readable.
You can immediately tell this function can take any number of arguments. + + +##### Another rest params example +```javascript +function addStuff(x, y, ...z) { + return (x + y) * z.length +} + +console.log(addStuff(1, 2, "hello", "world", true, 99)); +// 12 +``` + +### Spread + +The **spread operator** allows us to *split* and Array argument into individual elements. + +```javascript +let random = ["Hello", "world", true, 99]; +let newArray = [1,2, ...random, 3]; + +console.log(newArray); +//[1,2,"Hello","world",true,99,3] +``` + +Another example, *spreading* out the characters in the `hi` variable + +```javascript +var hi = "Hello World" +var hiArray = [ ...hi ] + +console.log(hiArray); +// ["H","e","l","l","o"," ","W","o","r","l","d"] +``` + +### Rest vs Spread + +Though the syntax is virtually the same, **rest** and **spread** serve different purposes... + +- **rest** + - gathers values and stores them in an array + - is used in function signatures (as an argument) +- **spread** + - spreads the values into individual array items + - used in the function body + + +##### Rest Example +```javascript +function restExample(...z) { + console.log(z) +} + +restExample("hello world") +//["hello world"] +``` + +##### Spread Example + +```javascript +function spreadExample(item) { + let spreadArray = [...item] + console.log(spreadArray); +} + +spreadExample("Hello World"); +// ["h","e","l","l","o"," ","w","o","r","l","d"] +``` + +## Exercise + +- complete exercises 18 - 21 (Rest and Spread operators) at [ES6Katas](http://tddbin.com/?229#?kata=es6/language/rest/as-parameter) + +## Destructuring + +### Arrays + +With **destructuring** you can store array items as individual variables during assignment. + +Consider the following examples: +##### *the old-fashioned way* +```javascript +var students = ["Julian", "AJ", "Matt"]; +var x = students[0]; +var y = students[1]; +var z = students[2]; + +console.log(x, y, z); +// Julian AJ Matt +``` +##### *the ES2015 way* + +```javascript +let students = ["Julian", "AJ", "Matt"]; +let[x,y,z] = students + +console.log(x,y,z); +// Julian AJ Matt +``` + +As you can see, this incredibly useful and readable. It also allows for scalability of your code. + +**Destructuring** also allows you to omit values + +```javascript +let students = ["Julian", "AJ", "Matt"]; +let[ ,y,z] = students + +console.log(y,z); +// AJ Matt +``` +```javascript +let students = ["Julian", "AJ", "Matt"]; +let[x,,y] = students + +console.log(x,y); +// Julian Matt +``` +### Using destructuring with rest parameters + + +Now that you know how to use destructuring with and rest parameters, how would you implement both concepts + +```javascript +let students = ["Julian", "AJ", "Matt"]; +let[x, ...rest] = students; + +console.log(x, rest); +// Julian ["AJ","Matt"] +``` + +### Array destructuring with functions +How would this work with functions? + +```javascript +function completedHomework(){ + return ["Julian", "AJ", "Matt"]; +} + +let [x,y,z] = completedHomework(); +console.log(x,y,z); +``` + +### Objects + +**Destructuring** also works with objects + + +```javascript +let instructor = { + name: "Shane", + email: "shane@techtalentsouth.com" +} +let { name: x , email: y } = instructor; + +console.log(x); +// Shane +``` + +### Bringing it all together + +Let's use destructuring and default parameters in a function: + +```javascript +let instructor = { + name: "Shane", +} + +function teacher({name, email = "info@techtalentsouth.com"}) { + console.log(name, email) +} + +teacher(instructor); +// Shane info@techtalentsouth.com +``` + +## Exercise + +- complete challenges 10-15 (Destructuring) at [ES6Katas](http://tddbin.com/?183#?kata=es6/language/destructuring/array) + +## Map, Set, WeakMap, WeakSet + +**Map** is a new way to store **key/value** pairs, while similar to objects **Map** is a bit more reliable when storing key/values. *This is due to the fact that Objects convert both keys and values to strings.* + +According to [Mozilla](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map) +> The Map object is a simple key/value map. Any value (both objects and primitive values) may be used as either a key or a value. + +```javascript +let student = {name: "Latori"}; +let status = new Map(); + +status.set(name, "Latori"); +status.set("feeling", "awesome") +console.log(status.get(name)); +console.log(status.get("feeling")) +//Latori +//awesome +``` +- to set a value use `set` +- to get an object use `get` + +**Set** is a collection of unique values + +```javascript +let student = new Set(); +student.add('Katy').add({mood: "happy"}); + +console.log(student); +// ["Katy",{"mood":"happy"}] +``` + +**WeakMap** works like **Map**, with a few small differences. + +- The keys must be objects +- Allows for garbage collection of keys +- does not allow iteration + +```javascript +let weakMap = new WeakMap(); +let student = {} +weakMap.set(student,"Lee"); + +console.log(weakMap.get(student)); +// Lee +``` + +**WeakSet** + +Like WeakMap for Sets + +```javascript +let weakSet = new WeakSet(); +let student = { + name: "Heather" +}; +weakSet.add(student); + +console.log(student); +// {"name":"Heather"} +``` + +## Arrow Functions + +If you remember from lesson #5 when dealing with callbacks, you have to implement some work-arounds to keep the appropriate lexical scope. + +As a refresher: + +```javascript +var teacher = { + name: 'Shane', + speak: function() { + + var boundFunction = function(){ + console.log('later my name is ' + this.name); + } + + setTimeout(boundFunction,1000); + } +} + +teacher.speak(); +// later my name is +``` + +Obviously, this is not the intended result we're looking for. In ES5 there are several ways to produce the desired results. + +##### *the old-fashioned way* +```javascript +var teacher = { + name: 'Shane', + speak: function() { + + //Bind a function to a specific context + var boundFunction = function(){ + console.log('later my name is ' + this.name); + }.bind(this); + + //boundFunction will always run in bound context + setTimeout(boundFunction,1000); + } +} + +teacher.speak(); +// later may name is Shane +``` + +While this works, it feels like a hack. + +Thankfully ES2015 solves the problem with **arrow functions** + +##### *the ES2015 way* +```javascript +var teacher = { + name: 'Shane', + speak() { + let boundFunction = () => { + console.log('later my name is ' + this.name); + } + + setTimeout(boundFunction,1000); + } +} + +teacher.speak(); +//later my name is Shane +``` + +Doesn't that feel better? the syntax involves: + +- removing the `function` keyword +- adding `()` and any appropriate arguments +- using the `=>` operator +- wrapping your function body in `{}` + +This introduces the concept of *lexical binding*.
+Which simply means: **arrow functions bind to the scope of where they are *defined* not where they are used** + + +##### with an argument +```javascript +var students = [ + { name: "Edwin"}, + { name: "Kim"}, + { name: "Skip"} + ]; + +var names = students.map((student) => {return student.name}); + +console.log(names); +// ["Edwin","Kim","Skip"] +``` + +## Exercise + +- Make the tests pass for #5 and #6 (arrow functions) at [ES6Katas](http://tddbin.com/?118#?kata=es6/language/arrow-functions/basics) + +## Classes + +One of the most interesting/exciting features of ES2015 is the introduction of Object Oriented Keywords. +The benefit of this feature, is that developers more accustomed to Object Oriented Programming can more easily work with Constructors and Prototypes. + +*note: the class features simply syntactic sugar, not an actual change to the functional nature of JavaScript* + +##### *the old-fashioned way* +```javascript +function Person (name, job) { + this.name = name; + this.job = job; +}; + +Person.prototype.getName = function getName () { + return this.name; +}; + +Person.prototype.getJob = function getJob () { + return this.job; +}; +var goodGuy = new Person('Jim Gordon', 'Commissioner'); +console.log(goodGuy.getName()); +// Jim Gordon +``` + +##### *the ES2015 way* +```javascript +class Person { + + constructor (name, job) { + this.name = name; + this.job = job; + } + + getName () { + return this.name; + } + + getJob () { + return this.job; + } +} + +let goodGuy = new Person('Jim Gordon', 'Commissioner'); +console.log(goodGuy); +//Jim Gordon +``` + +For those of you that have experience in Ruby or Python, this syntax should look and feel familiar. + +- Use the `class` keyword followed by a capitalized name +- add a constructor function +- add instance methods that give you access to the object's properties + +### Inheritance + +This syntatic sugar also provides a really nice and clean way to create inheritance chains + +*note remember that JS inhertance is still instance based (not class based)* + +##### the old-fashioned way +```javascript +function Person (name, job) { + this.name = name; + this.job = job; +}; + +Person.prototype.getName = function getName () { + return this.name; +}; + +Person.prototype.getJob = function getJob () { + return this.job; +}; + +function SuperHero (name, heroName) { + Person.call(this, name, heroName); +} + +SuperHero.prototype = Object.create(Person.prototype); +SuperHero.prototype.constructor = SuperHero; + +SuperHero.parent = Person.prototype; +SuperHero.prototype.getJob = function () { + return 'I am '+ this.job + "!" +}; + +var batman = new SuperHero('Bruce Wayne', 'Batman'); + +console.log(batman.getJob()); +``` + +As you can see, this is pretty verbose. Let's take a look at the ES2015 way + +##### *the ES2015 way* +```javascript +class Person { + + constructor (name, job) { + this.name = name; + this.job = job; + } + + getName () { + return this.name; + } + + getJob () { + return this.job; + } +} + +class SuperHero extends Person { + + constructor (name, heroName, superPower) { + super(name); + this.heroName = heroName; + this.superPower = superPower; + } + + secretIdentity(){ + return `${this.heroName} is ${this.name}!!!` + } + +} +let batman = new SuperHero("Bruce Wayne", "Batman"); + +console.log(batman.secretIdentity()) +// Batman is Bruce Wayne!!! +``` + +The 3 things that you'll notice: + +- create a new SuperHero `class` +- use the `extends` keyword to indicate you want to inherit from the Person `class`
*after all, superhero's are People too* +- the use of `super()` allows us to: + - reuse the exisiting `name` functionality from the Person `class` + - add superhero specific features to our constructor function + +### Getters and Setters + +If you have experience with Object Oriented programming, chances are you're familiar with *getters* and *setters* + +Getters allow us to easily **read** (access) an object's property.
+Setters allow us to **write** (modify) an object's property. + + +```javascript +class Person { + + constructor (name) { + this.name = name; + } + + set name (name) { + this._name = name; + } + + get name () { + return this._name + } + +} + +let goodGuy = new Person('Jim Gordon'); +console.log(goodGuy.name); +// Jim Gordon + +goodGuy.name = "James Gordon"; +console.log(goodGuy.name); +// James Gordon +``` + +### Other nifty features + +- ES2015 gives us a new way to easily add existing variables to objects. + +```javascript +let name = "Shane"; +let job = "Developer"; + +let instructor = { name, job }; + +console.log(instructor); +// {"name":"Shane","job":"Developer"} +``` + + + +## Modules + +As you know, we've already talked about Modules quite a bit.
+ES2015 offers a module syntax that encapsulates our code. + +This provides several significant benefits including: + +- avoids naming conflicts +- removes global variables +- better control over scope +- better control over 3rd party libraries +- logical load order +- faster tests + +To many, this is the most exciting feature of ES2015 + +Modules consist of **export** and **import** statements + +According to Mozilla: + +Export: + +> ...is used to export functions, objects or primitives from a given file (or module). + +Import: + +> ...is used to import functions, objects or primitives that have been exported from an external module, another script, etc. + + +let's take a look some basic examples: + + +##### exporting a single function +```javascript +// ./src/calculator.js + +export function add(...numbers) { + let sum = 0; + numbers.forEach(function (number) { + sum += number; + }); + return sum; +} +``` + +```javascript +// .src/index.js + +import {add} from './calculator'; + +console.log(add(1,2,3)); +``` + + +##### exporting multiple items +```javascript +// ./src/calculator.js + +export function add(...numbers) { + let sum = 0; + numbers.forEach(function (number) { + sum += number; + }); + return sum; +}; + +export function subtract(x,y) { + return x - y; +}; +``` + +```javascript +// .src/index.js + +import {add, subtract} from './calculator'; + +console.log(add(1,2,3)); +console.log(subtract(6,2)); +``` + +**Variables and Constants can also be exported** + +```javascript +// ./src/calculator.js + +export const numbersArray = [1,2,3,4,5]; +``` + +```javascript +// ./src/index.js + +import _ from 'lodash'; + +console.log(_.shuffle(numbersArray)); +``` + +**Default Exporting** allows you to set one item as default. This is helpful with a module or class that returns a single value + +```javascript +// ./src/calculator.js + +export default function add(...numbers) { + let sum = 0; + numbers.forEach(function (number) { + sum += number; + }); + return sum; +}; +``` + +```javascript +// ./src/index.js + +import add from './calculator'; + +console.log(add(1,2,3)); +``` + +Only one default can be clarified per module.
+Modules can, however, have default and named exports + +```javascript +// ./src/calculator.js + +export default function add(...numbers) { + let sum = 0; + numbers.forEach(function (number) { + sum += number; + }); + return sum; +}; + +export function subtract(x,y) { + return x - y; +}; + +``` + +```javascript +// ./src/index.js + +import add, {subtract} from './calculator'; + +console.log(add(1,2,3)); +console.log(subtract(6,2)); +``` + +One final way to import is by using the `*` (all, wildcard) operator. This syntax will import all exports. + +```javascript +// ./src/calculator.js + +export function add(...numbers) { + let sum = 0; + numbers.forEach(function (number) { + sum += number; + }); + return sum; +}; + +export function subtract(x,y) { + return x - y; +}; +``` + +```javascript +// ./src/index.js + +import * as calculate from './calculator'; + +console.log(calculate.add(1,2,3)); +console.log(calculate.subtract(6,2)); +``` + +As you can see, writing modular code is the future of JavaScript. The modular pattern will be heavily used as we move into building applications with React. + + +## Exercise && Homework + +- complete the NodeSchool [tower-of-babel](https://github.com/yosuke-furukawa/tower-of-babel) module +- complete [this](http://ccoenraets.github.io/es6-tutorial/ecmascript6-setup-babel.html) ES2015 tutorial +- push the code to our class GitHub (name the project yourName_ES6) + + +## Reading + +[YDKJS](https://github.com/getify/You-Dont-Know-JS/tree/master/es6%20%26%20beyond#you-dont-know-js-es6--beyond) + +[For and Against Let](https://davidwalsh.name/for-and-against-let) + +[ES2015 Constants](https://mathiasbynens.be/notes/es6-const) + +[Map, Set, WeakMap, WeakSet](http://www.2ality.com/2015/01/es6-maps-sets.html) diff --git a/lesson 13 - React Part1.md b/lesson 13 - React Part1.md new file mode 100644 index 0000000..75898dc --- /dev/null +++ b/lesson 13 - React Part1.md @@ -0,0 +1,281 @@ +# Lesson 13 - React + +## Recap & Intro +- We've come a long way! We've learned + - JavaScript Basics + - Browser & DOM + - API's and Async + - Application setup & Compilation +- At this point we have all the concepts we need +- Today, we learn about React! + +## What is React? + +- Open source view framework developed by Facebook +- React lets you define interfaces in JavaScript +- React can render anywhere to anything +- Simple, powerful, and composable + +## What React Isn't +- React is not a web framework (not tied to html/css). +- React isn't a full fledged application framework +- React is not Flux or Redux + +## Core concepts + +### Components +Everything in React is a component. Think of a component as custom html tag that renders its own interface and comes packaged with its own behavior (click events, etc) + + +### Virtual DOM +When you render a React component, it renders to a virtual representation of the interface in memory. This is called the "Virtual DOM". React then uses any number of open source plugins to render the virtual DOM state to an interface like the real DOM, a canvas, or a native mobile app. + +### ReactDOM +The library we'll be using to render React components to an HTML document is called reactDOM. ReactDOM converts your React state to HTML. It manages the HTML and event handlers for you so that subsequent renderings of your application make the fewest possible changes to the actual DOM, increasing performance. + +**Important** - React abstracts away the DOM interface. You're not really writing HTML. + +### JSX +Most React code is written in a superset of JavaScript called JSX. It lets you create components in your JS code in a way that looks more familiar (like HTML). Keep in mind, this IS NOT HTML. It's also not really JS. It needs to be compiled by webpack into a .js file that a browser can read. + + +## Defining & Rendering Components +Let's define our first component. + +```javascript +import React from 'react'; +import ReactDOM from 'react-dom'; + +class HelloMessage extends React.Component { + render() { + return ( +
Hello World
+ ); + } +} +var mountPoint = document.querySelector('#app'); +ReactDOM.render(, mountPoint); + +``` + +A few things to note: + +- We are importing React and ReactDOM separately. +- We are using ES6 class syntax to define a new component class that inherits from React's default component +- We are defining a `render` method, which is the only method required to define a component class. +- The render method returns a React component. Use parens to allow multi-line component definitions, and make sure you're returning a single root component. The root component can have children, but not siblings. +- We are using ReactDOM to render an *instance* of our class to an element on the html document. + +### JSX Caveats +Like we said before, JSX isn't really HTML. Because it lives in the same context as JavaScript, it has some special rules you need to follow when returning components from your render method. + +- Attributes with the same names as reserved JS keywords can't be used. For example `class` and `for` are changed to `className` and `htmlFor` in JSX. +- All tags have to be closed. `` for example, has to include a closing tag ``. + +## Exercise 1: Rendering a Simple Component +Let's create our first component! + +1. Clone the boilerplate project from `git@github.com:ttsJavaScriptApps/webpack-boilerplate.git` +2. In index.jsx, create a component class called `MessageInput` that renders: + 1. A text input called + 2. A label for the text input (clicking it should focus the input) + 3. A 'send' button +3. Render an instance of your component to the DOM. + +## Making our JSX Dynamic +Let's take a deeper look at the render method. This is essentially the equivalant of our view template in other frameworks (ejs, handlebars, mustache, jade, haml, etc.). + +The basic functionality needed in any templating language is + +1. Token Replacement +2. Conditions +3. Iteration + +Let's take a look at how we do that in JSX. + +### State +Before we make our templates dynamic we need data to drive them. The data that components need to render is kept in a special property object called `state`. + +We add a constructor method to define our component's state object. + +```javascript +class HelloMessage extends React.Component { + + constructor() { + super(); //needed for inheritance + + //Define an intial state object + this.state = { + message : 'Hello World' + }; + } + + render() { + return ( +
Hello World
+ ); + } +} +``` + +Now that we have data, we can start making our templates dynamic. + +### Token Replacement +Token replacement is simply taking variables and putting their value into the template. In JSX, use curly braces with a variable name: + +```javascript +// this.state = { message : 'Hello World'}; +render() { + return ( +
{this.state.message}
+ ); +} +``` + +Tokens don't have to come exlusively from state. They can be calculated. e.g. + +```javascript +render() { + var statement = "message is: " + this.state.message; + return ( +
{statement}
+ ); +} +``` + +### Conditions +Often times we want to render one thing in one case, and something else in another case. There are a couple of ways to do this with JSX + +#### Use JavaScript! + +```javascript +// this.state = { person : 'Matt'}; + +render() { + + //Figure out the elements in advance + if(this.state.person) + message = "Hello " + this.state.person; + else + message = "I'm all alone... and sad"; + + return ( +
{message}
+ ); +} +``` + +### Inline +If you prefer an inline look to your template, remember, you can run functions inside those curly braces. Use an IIFE to generate the value you want + +```javascript +render() { + return ( +
+ {(() => { + if(person) + return "Hello " + this.state.person; + else + return "I'm all alone... and sad"; + })()} +
+ ); +} +``` + +### Iterative Rendering +Sometimes you want to render the same elements repeatedly for every item in an array. JSX lets you put an array of components inside the `{}` for rendering. All you have to do is create it based on the data you want to render. + +```javascript +//this.state = { studentNames: ['Matt', 'Katy', 'Mariel', 'Lee'] } + +render() { + //Figure out the elements in advance + var students = this.state.studentNames.map(function(name){ + return (
  • {name}
  • ) + }) + + return ( + + ); +} +``` + +Something to note above is the use of the `key` property. In order for React to keep track of and property update dynamically generated elements, give them a unique "key". Above, we're using the student name, which isn't guaranteed to be unique, so be careful choosing your key. + +## Dynamic Class Names +One of the most common dynamic elements is the list of classes an element has applied. The simple way to do this is to use javascript logic to concat a string. + +```javascript +//this.state = {active: true} + +render() { + var classes = 'item' + + if(isActive) { + classes += 'active'; + } + + + return ( +
    + ); +} + +``` + +A better approach is to use the 'classnames' module + +```javascript +import classNames from 'classnames'; + +render() { + var classes = classNames({ + 'item' : true, + 'active' : isActive + }) + + return ( +
    + ); +} + +``` + +## Inline styles +Because React brings HTML, CSS, and JS into the same context, you can use POJOs(Plain ol' JavaScript Objects) as styles for your components! + +```javascript +render() { + var headerStyle = { + color: 'red', + textDecoration: 'underline' + } + + return ( +

    + ); +} +``` + +You can define styles in another module and import them. + +## Exercise 2: Rendering Components with Logic +Let's add some logic to our little component. + +1. Declare an array of message objects with properties for `text`, `time`, and `user` +2. Add a `ul` with an `li` element for each message containing the message, user's name and timestamp. +3. Declare a variable `currentUser` and set it to one of the users in the messages array +4. If a message's author is the `currentUser`, add a class to it that turns the message red. +5. Only show the most recent 3 messages. +6. If there are more than 3 messages, show a "load more" button + +## Homework + +- Start Reading the [React Documentation](https://facebook.github.io/react/docs/getting-started.html) +- Complete the first 3 challenges (stop at Step 2 - Part 3) of [Thinking in React](https://github.com/asbjornenge/thinking-in-react) module + + +- [https://facebook.github.io/react/docs/getting-started.html](https://facebook.github.io/react/docs/getting-started.html) +- [https://www.nczonline.net/blog/2016/01/react-and-the-economics-of-dynamic-web-interfaces/](https://www.nczonline.net/blog/2016/01/react-and-the-economics-of-dynamic-web-interfaces/) +- [https://github.com/eanplatter/react-starter](https://github.com/eanplatter/react-starter) diff --git a/lesson 14 - React Part 2.md b/lesson 14 - React Part 2.md new file mode 100644 index 0000000..936ba0f --- /dev/null +++ b/lesson 14 - React Part 2.md @@ -0,0 +1,112 @@ +# Lesson 14 - React Part 2 + +## Recap & Intro + +- Last time we learned about rendering a component in React +- Today we'll continue learning about React components and composition + +## Event Handling +JSX has a similar event system to the DOM, but better. Because events are supplied by the React library, not the web browser, you get 100% consistency. No browser quirks! + +### Wiring up a handler + +```javascript +class HelloMessage extends React.Component { + + constructor() { + super(); + this.state = { + clickCount : 0 + }; + } + + _handleClick(event) { + console.log('clicked!', event) + } + + render() { + return ( + +
    {this.state.clickCount}
    + ); + } +} +``` + +### Updating state +A user event like a click probably means an update to your state. When updating state make sure to use `this.setState()` and not update state directly. This is how React keeps track of the fact that state is changing! + +```javascript +_handleClick(event) { + var clicks = this.state.clickCount; + this.setState({clickCount: clicks + 1}) + } + +``` + +## Forms and User Input +Forms are where the difference between classic DOM elements and JSX components becomes more evident. + +### Controlled Components + +Using the "value" property, this text input will ALWAYS have the value "Hello!", no matter what the user does + +``` +render() { + return ; + } +``` + +In order to let the user update its value, use the onChange event handler to update state. + +```javascript +_handleChange: function(event) { + this.setState({value: event.target.value}); +} + +render() { + return ( + + ); +``` + +### Uncontrolled Components +If you omit the value property, and use defaultValue instead, you get more familiar behavior. + +```javascript +render: function() { + return ; + } +``` + +### Refs +Because an uncontrolled component isn't bound to any value in our state, getting its value requires us to name it using a "ref" attribute + +```javascript + +_clickHandler(event) { + console.log(this.refs.message.value) +} + +render() { + return ( +
    + + +
    + ); + } +``` + +## Exercise 1: Handling Events + +1. Wire up a click event handler to your button. +2. Clicking the button takes the message from the text input and adds it to the message list. +3. Clicking the button clears the message from the input box. +4. If there is no text in the input box, the button should do nothing. +5. Add an edit button to messages sent by the current user. +6. Clicking the edit button sets a state property to the index of the item being edited diff --git a/lesson 15 - React Part 3.md b/lesson 15 - React Part 3.md new file mode 100644 index 0000000..281b46b --- /dev/null +++ b/lesson 15 - React Part 3.md @@ -0,0 +1,216 @@ +## Recap & Intro + +- The last 2 classes have been an intro to the basics of React +- We've covered: + - Components + - JSX + - Event Handlers + - State +- Tonight we'll continue by discussing: + - Component Composition + - Props + + +## Composition +Up to now we've done all of our work in a single component, but React's strength is to break up applications into many re-usable components and compose them. React components we define can be used the same way as built-in react components like `
    ` and `

    `. + +For example, if we define a ToDoItem component, we can re-use it in a ToDoList component. + +```javascript +class TodoItem extends React.Component { + constructor(){ + super(); + this.state = {text: "default text"} + } + render() { + return ( +
    {this.state.text}
    + ); + } +} + +class TodoList extends React.Component { + constructor(){ + super(); + this.state = {listItems: [ + {text: "Gym"}, + {text: "Tan"}, + {text: "Laundry"} + ]} + } + render() { + var comps = this.state.listItems.map(function(item){ + return + }) + + return ( +
    {comps}
    + ); + } +} +``` + +## Props +In the previous example, you probably noticed that we didn't pass any data from our `listItems` to our child components. We can do this using Props. + +From HTML, we're familiar with the concept of "properties" that configure an element's behavior. For example, an `` tag accepts properties including `href` and `name` that are supplied by user of the element + +``` + +``` + +React components have a similar concept called `props`. Props are JavaScript objects supplied by creator of a component instance. + +##### A Simple Example +```javascript +import React from 'react'; +import ReactDOM from 'react-dom'; + +class HelloMessage extends React.Component( + render() { + return
    Hello {this.props.name}
    ; + } +); +ReactDOM.render(, + document.getElementById('root')); +``` + + +### Passing Props to Children + +```javascript +class ChildComponent extends React.Component{ + render() { + return
    + I am {this.props.color} +
    + } +} + +class ParentComponent extends React.Component{ + render() { + return ( + + ); + } +) + +ReactDOM.render( + , + document.getElementById('root')); +``` + + + +### Passing JS Objects as Props +In the previous example we passed a simple string in as the property value like we're used to doing in HTML. With JSX, you can pass any JS object in as a property. This includes objects, arrays, and even functions! + + +#### todoList.jsx +```javascript +class TodoList extends React.Component { + constructor() { + super(); + this.state = {listItems: [ + {text: "Gym"}, + {text: "Tan"}, + {text: "Laundry"} + ]} + } + render() { + var comps = this.state.listItems.map(function(item, i ){ + return + }) + + return ( + {comps} + ); + } +} + +class TodoItem extends React.Component { + render() { + return ( +
    {this.props.item.text}
    + ) + } +} + + +ReactDOM.render( + , + document.getElementById('root')); +``` + +### Passing Functions as Props +Remember, functions are Objects! This means you can pass them in as props as well. This is a very powerful feature. + +```javascript +class TodoList extends React.Component { + constructor() { + super(); + this.state = {listItems: [ + {text: "Gym"}, + {text: "Tan"}, + {text: "Laundry"} + ]} + } + completeItem(item) { + console.log('completed item', item); + } + + render() { + var comps = this.state.listItems.map((item,i) => { + return + }) + + return ( + {comps} + ); + } +} + +class TodoItem extends React.Component { + constructor() { + super(); + } + + render() { + return ( +

    {this.props.item.text}

    + ) + } +} +``` + +### Default Props +You can set default values for properties by setting a `defaultProps` property on the class. + +```javascript +TodoItem.defaultProps = {text: "default text"} +``` + +### Validating Props +You can also specify the types of properties +```javascript +TodoItem.propTypes = { item: React.PropTypes.object }; +``` + +## Exercise 1: Composition +Let's break apart our monolithic component a bit. + +1. Create a component that displays a single message based on a "message" object prop. +2. Validate that the message prop is an object using `propTypes` +3. Refactor your main component to use the message component to display messages. +4. Create a component for your message inputs (text and save button) +5. Refactor your main component to use the messageInputs component + - Make sure all buttons and events still work as expected. + + +# Homework + +- finish the [Thinking In React](https://github.com/arkency/reactjs_koans) module +- Pass the first 4 [React Koans](https://github.com/arkency/reactjs_koans) tests diff --git a/lesson 16 - React Part 4.md b/lesson 16 - React Part 4.md new file mode 100644 index 0000000..3512c07 --- /dev/null +++ b/lesson 16 - React Part 4.md @@ -0,0 +1,542 @@ +# React Component LifeCycle & React Router + + +## Recap & Intro +- Last week focused on: + - State + - Props + - Component Composition +- Tonight we'll be discussing React LifeCycle and React Router + + +## Agenda + +- Cover the full spectrum of LifeCycle events in React +- Discuss how to render different views (in a single page application) + +## Lifecycle events + +So, what are Component LifeCycle Events? While it sounds scary, the concept is actually quite simple. + +Below are the 4 stages of the React LifeCycle: + +![](./images/react_lifecycle.png) + +Before we dive in though, let's review props and state + +### Props vs State + +#### Review of Props and State + +If a Component needs to alter one of its attributes at some point in time, that attribute should be part of its state, otherwise it should just be a prop for that Component. + +**props**: + +props (short for properties) are a Component's configuration, its options if you may. They are received from above and immutable as far as the Component receiving them is concerned. + +A Component cannot change its props, but it is responsible for putting together the props of its child Components. + +**state**: + +The state starts with a default value when a Component mounts and then suffers from mutations in time (mostly generated from user events). It's a serializable* representation of one point in time—a snapshot. + +A Component manages its own state internally, but—besides setting an initial state—has no business fiddling with the state of its children. You could say the state is private. + +## Component Initialization + +You are familiar with the instantiation of a component. + +```javascript +class HelloMessage extends React.Component { + constructor(){ + super(); + } + + render(){ + return( +

    Hello World

    + ) + } +} +``` + +When a component is instantiated, the `render()` method - along with 4 other methods - are called. + +Those methods are: + +- `getInitialState()` ***this has been deprecated in favor of `this.state` in your constructor method*** +- `getDefaultProps()` ***(also deprecated in favor of ES6 instance methods)*** +- `componentWillMount()` +- `componentDidMount()` + +Obviously, you understand render, so lets dig into the other methods + +### this.state = {} + +As stated above, `getInitialState` has been replaced with `this.state`, however, I believe that looking at the `getInitialState` syntax will help bring a bit of clarity to the LifeCycle + +Let's create a basic counter that, when clicked, will count up + +##### with: getInitialState +```javascript +var Counter = React.createClass({ + getInitialState: function() { + console.log('getInitialState just ran!'); + return {count: 0}; + }, + + countUp: function() { + this.setState({count: this.state.count + 1}); + }, + + render: function() { + return ( +
    +

    {this.state.count}

    +
    + ) + } +}); + +let mountPoint = document.getElementById("root"); +ReactDOM.render(, mountPoint) +``` + +`getInitialState` fires as soon as the component is instantiated. However, it does not run again throughout the life of the component. + + +let's throw a couple of `console.log()`'s in to further illustrate the point. + +```javascript +var Counter = React.createClass({ + getInitialState: function() { + console.log('getInitialState just ran!') + return {count: 0}; + }, + ... + render: function() { + console.log('render just ran!'); + return ( + ... + ) + } +}); +``` + +In an effort to make React line up more with ES2015 (and future versions of JavaScript) `getInitialState` has been replaced with simply declaring `this.state =` in your constructor method. + + +##### with: this.state +```javascript +class Counter extends React.Component { + constructor(props) { + super(props); + this.state = {count: 0}; + console.log('state has been intialized!'); + } + + countUp() { + this.setState({count: this.state.count + 1}); + } + + render() { + console.log('render just ran!'); + return ( +
    +

    Clicks: {this.state.count}

    +
    + ); + } +} + +let mountPoint = document.getElementById("root"); +ReactDOM.render(, mountPoint) +``` + +### defaultProps + +As stated in the intro, `defaultProps` was formerly known as `getDefaultProps` + +`defaultProps` does exactly what you would think... it defines default props being made available to the component. + +Assigning default props is as simple as declaring `YourClass.defaultProps` and passing an object. + +```javascript +class Counter extends React.Component { + constructor(props) { + super(props); + console.log('State has been intialized!'); + this.state = {count: this.props.initialCount}; + console.log('Default Props assigned!'); + } + countUp() { + this.setState({count: this.state.count + 1}); + } + render() { + console.log('render just ran!'); + return ( +
    +

    Clicks: {this.state.count}

    +
    + ); + } +} + +Counter.propTypes = { initialCount: React.PropTypes.number }; +Counter.defaultProps = { initialCount: 0 }; +``` + +`defaultProps` and `propTypes` are considered properties on the constructor method. Which is why we can pass props to `super()` + +### componentWillMount + +`componentWillMount` is called *before* `render` is executed + +This is the part of the lifecycle where props and state values are interpreted to create the correct output. Meaning that state/props should should be modified inside this function. + +According to the [React Documentation](https://facebook.github.io/react/docs/component-specs.html): +> If you call `setState` within this method, `render()` will see the updated state and will be executed only once despite the state change. + +```javascript +class Counter extends React.Component { + ... + + componentWillMount(){ + console.log('componentWillMount just ran!'); + } + render() { + ... + } +} +``` + +### componentDidMount + +Immediately after the `render` method has been invoked, the `componentDidMount` function is called. + +`componentDidMount` is where you should place your DOM interactions and AJAX calls. + +```javascript + class Counter extends React.Component { + + ... + + componentDidMount(){ + console.log('componentDidMount just ran!'); + setTimeout(function(){ + console.log('running the setTimeout method!'); + }, 2000); + } + + render() { + ... + } +} +``` + +This summarizes the LifeCycle events being triggered during Component Instantiation. + +## setState and props Changed + +`setState` triggers the state change LifeCycle events, while updates to props triggers the `componentWillReceiveProps` method + +Updates to **state** and **props** contain 3 additional LifeCycle methods: +- `shouldComponentUpdate` +- `componentWillUpdate` +- `componentDidUpdate` + +### shouldComponentUpdate + +`shouldComponentUpdate` is **boolean** method that isalways called before `render`. + +The purpose of `shouldComponentUpdate` is to determine if re-rendering is needed. + +`shouldComponentUpdate` takes 2 arguments: + +- nextProps +- nextState + +These arguments are used to detect when re-rendering is needed. + +```javascript +class Counter extends React.Component { + + ... + + shouldComponentUpdate(nextProps, nextState){ + console.log(`shouldComponentUpdate is running! + nextState: ${JSON.stringify(nextState)}`); + + return true; + } + render() { + ... + } +} +``` +*note: if the `shouldComponentUpdate` method is invoked, you must return a boolean value* + +### componentWillUpdate + +As soon as `shouldComponentUpdate` returns `true`, `componentWillUpdate` is invoked. In many ways, you could consider this a cousin to the `componentWillMount` method. + +Calls to to trigger state changes, (ie: `this.setState`) are not allowed in `componentWillUpdate`. + + +Think of `componentWillUpdate` as a way to prepare for upcoming changes to state. + +```javascript +class Counter extends React.Component { + ... + + componentWillUpdate(nextProps, nextState){ + console.log(`preparing for the upcoming state change! + this.state: ${JSON.stringify(this.state)} + nextState: ${JSON.stringify(nextState)}`); +} + + render() { + ... + } +} +``` + +### componentDidUpdate + +At this point, you should be able to pretty clearly guess the behavior of `componentDidUpdate`. + +The functionality of `componentDidUpdate` is very similar to `componentDidMount`(with the exception that `componentDidUpdate` is called each time the component is re-rendered). Any interactions with the DOM (after re-rendering) should take place within this method + +Additionally, you'll notice that `prevProps` and `prevState` are passed as arguments + +```javascript +class Counter extends React.Component { + ... + +componentDidUpdate(prevProps, prevState) { + console.log('componentDidUpdate just ran!'); +} + + render() { + ... + } +} +``` + +### componentWillReceiveProps + +`componentWillReceiveProps` runs prior to the above state change methods and is only invoked when changes are made to props. + +Before we go any further, let's change up the code and try out a new example with multiple components. + +#### index.js +```javascript +import React from 'react'; +import ReactDOM from 'react-dom'; + +writeToScreen('Initial', 'primary'); + +class Counter extends React.Component{ + constructor(props){ + super(props); + writeToScreen('GetInitialState', 'info'); + writeToScreen('GetDefaultProps', 'info'); + this.state = { + foo : 1 + }; + } + + componentWillMount() { + writeToScreen('ComponentWillMount', 'warning'); + } + + componentDidMount() { + writeToScreen('ComponentDidMount', 'warning'); + } + + shouldComponentUpdate() { + writeToScreen('ShouldComponentUpdate', 'info'); + return true; + } + + componentWillReceiveProps(nextProps) { + writeToScreen('ComponentWillRecieveProps', 'warning'); + } + + componentWillUpdate() { + writeToScreen('ComponentWillUpdate', 'warning'); + } + + componentDidUpdate() { + writeToScreen('ComponentDidUpdate', 'warning'); + } + + componentWillUnmount() { + writeToScreen('componentWillUnmount', 'danger'); + } + +updateState() { + writeToScreen('Updating State', 'primary'); + this.setState({foo: this.state.foo + 1}); +} + +render(){ + writeToScreen('Render', 'success'); + return ( +
    +

    This.state.foo: {this.state.foo}

    +

    This.props.bar: {this.props.bar}

    +
    + + +
    + )} +} + +Counter.defaultProps = { bar: 0 }; + +class App extends React.Component{ + constructor(){ + super(); + this.state = {id : 1}; + } + + unmount() { + writeToScreen('Unmounting', 'primary'); + ReactDOM.unmountComponentAtNode(document.getElementById('root')); + } + + updateProps() { + writeToScreen('Updating Props', 'primary'); + this.setState({id: this.state.id + 1}); + } + + render() { + return ( +
    +
    + +
    + + +
    + +
    + ) + } +} + +function writeToScreen(msg, level) { + var elem = document.getElementById('screen'); + elem.innerHTML += '
    ' + + '   ' + + msg + + '
    '; +} + +let mountPoint = document.getElementById("root"); +ReactDOM.render(, mountPoint) +``` + +#### index.html +```html + + + + + + + + + + + +
    +
    + + + +``` + +*At this point, it would be better to switch to the React Dev Tools to inspect the state and props of each component* + +Above, we are calling the `componentWillReceiveProps` method each time we click the Update Props button. + +This method runs and each subsequent state change method is invoked afterwards. + +### componentWillUnmount + +Again, you should have a pretty clear sense of what `componentWillUnmount` is going to accomplish. + +This method removes the component from the DOM. + +In your `` component, add the following: + +```javascript +class App extends React.Component{ + constructor(){ + ... + } + unmount() { + writeToScreen('Unmounting', 'primary'); + ReactDOM.unmountComponentAtNode(document.getElementById('root')); + } + + updateProps() { + ... + } + + render() { + return ( +
    +
    + +
    + + +
    + ) + } +} +``` + +For fun, we can also add the following code to our `App` component: + +```javascript + componentDidUpdate(prevProps, prevState) { + setInterval(this.updateProps.bind(this),500); + } +``` + +This will show that our app will continue to make calls even after the app is no longer mounted. While it serves no *real* purpose, this should show you the power of Mounting/UnMounting Components. + + + +Now that you've had a chance to review the React LifeCycle, let's look at a more detailed image: + +![](./images/full_component_lifecycle.png) + + +## Homework + +- Complete the [ReactJS Koans](https://github.com/arkency/reactjs_koans) exercies +- Read the following article on [shouldComponentUpdate](http://buildwithreact.com/article/optimizing-with-shouldcomponentupdate) diff --git a/lesson 17 - React Part 5.md b/lesson 17 - React Part 5.md new file mode 100644 index 0000000..3be56fe --- /dev/null +++ b/lesson 17 - React Part 5.md @@ -0,0 +1,231 @@ +## React Router + + +## Intro & Recap + +- Last class, we discussed the React Component LifeCycle. +- This includes: + - Component Instantiation + - Updates to State + - Updates to Props + - Unmounting Components +- Which leads us into tonight's topic: React Router + +## Agenda + +- Understand the purpose of React Router +- When to use React Router +- How to implement React Router + +## The Purpose of React Router + +Due to the fact that React is a library (not a complete framework), it does not aim to solve all an application's needs. + +While React does a great job at creating components and providing a system for managing state (in Single Page Applications, you still need a way of changing URL's and rendering new components (based on User Interaction) + +The best solution for this is the React Router Library. + +According to the React Router Documentation: + +> React Router is a powerful routing library built on top of React that helps you add new screens and flows to your application incredibly quickly, all while keeping the URL in sync with what's being displayed on the page. + +In short, React Router takes care of rendering components for us. + +Let's dig in: + +### Install and Import React Router + +You'll need to install React Router through NPM + +`npm install react-router --save-dev` + +Next, you'll want to import the appropriate variables. + +```javascript +import React from 'react'; +import ReactDOM from 'react-dom'; +import { Router, Link, Route } from 'react-router'; + +``` + +That's it for setup! + + +### Component Configuration + +We're going to utilize 3 components + +Starting with a NavBar component + +```javascript +class NavBar extends React.Component{ + render(){ + return( +
    + Home + Login +
    + ) + } +} +``` +You'll notice here that we've used the `` component. This has been pulled directly from the React-Router library. + +- `` replaces `` +- This provides a standard HTML anchor tag when the DOM renders +- Using `` is **necessary** for React Router to implement the routing magic that we are looking for. + + + +Next, we'll create a Welcome Component, asking the user to Login + +```javascript +class Welcome extends React.Component{ + render() { + return ( +
    + +

    Press Login To Continue

    +
    + ); + } +} +``` + +In the above example, we've brought our NavBar component in as a child component. + + +Finally, we'll create a Login Component (for when the User is Logged In) + +```javascript +class Login extends React.Component{ + render() { + return( +
    + +

    You are now Logged In

    +
    + ); + } +} +``` + +### Configure the Routes + +While on the surface, this appears to be difficult, it's surprisingly simple + +Step one is creating the Router + +```javascript +let routes = ( + +) +``` +We've assigned the `` component to a variable named `routes` + + +Next, we'll nest ``'s as children of the `` + +```javascript +let routes = ( + + + + +); +``` + +### Render the Router + +In our ReactDOM.render method, we'll just need to pass in the `routes` variable as our first argument + +```javascript +let mountPoint = document.getElementById("root"); +ReactDOM.render(routes, mountPoint) +``` + +This allows React Router to handle rendering the appropriate components. + +### History + +You've probably noticed that the URL bar has really random strings appended to the end of your URI. This is through a concept known as hashHistory. Essentially, the `#` is used to manage routing performed on the client side. + +Currently, The React Router documentation recommends using `browserHistory` to address this issue, and clean up the URL's. + +```javascript +import { Router, Link, Route, browserHistory } from 'react-router'; + + ... + +let routes = ( + + ... + +); +``` + +With browserHistory implemented, your `` component knows which *history tracking* stragety to use, and makes the URL looks significantly better. + + +## Exercise and Homework + +- Work with your partner to complete the [React Router Tutorial](https://github.com/ttsJavaScriptApps/React-Router-Tutorial) +- Clone the repo +- Create a new branch +- Push the changes back up to the class GitHub repo + + +### Full Code Sample: + +```javascript +import React from 'react'; +import ReactDOM from 'react-dom'; +import { Router, Link, Route, browserHistory } from 'react-router'; + +class NavBar extends React.Component{ + render(){ + return( +
    + Home + Login +
    + ) + } +} + +class Welcome extends React.Component{ + render() { + return ( +
    + +

    Press Login To Continue

    +
    + ); + } +} + + +class Login extends React.Component{ + + render() { + return( +
    + +

    You are now Logged In

    +
    + ); + } +} + + +let routes = ( + + + + +); + + +let mountPoint = document.getElementById("root"); +ReactDOM.render(routes, mountPoint) +``` diff --git a/lesson 18 - Firebase.md b/lesson 18 - Firebase.md new file mode 100644 index 0000000..8baf634 --- /dev/null +++ b/lesson 18 - Firebase.md @@ -0,0 +1,333 @@ +# Lesson 18 - Firebase + +## Recap & Intro +- We've learned a lot about React +- Last lesson, we learned how to get data into our React components +- Today we'll learn how to integrate a real-time data source +- We'll also learn how to deploy our application + +## What is Firebase +Firebase is a back end as a service (BaaS) platform. It provides: + +- Hosting for your static application +- Data read/write +- User Authentication + +## Hosting +Your React app is static, meaning that it doesn't have to run any code on the server. All a server needs to do is host your files and provide them to a client when requested. Firebase does this for you easily. + + +## Exercise 1: Deploying your app +1. Sign up for firebase using your Google account at [http://www.firebase.io](http://www.firebase.io) +2. Install Firebase tools using your commandline - `npm install -g firebase-tools` +3. Log in to your firebase account from commandline `firebase login` +4. From your React application directory, create a new Firebase app by running `firebase init` (tell firebase where your dist directory is) +5. Deploy using `firebase deploy` +6. See your app by running `firebase open` + +## Data +A Firebase data store can be thought of simply as a JSON object in the cloud. When you create a Firebase application, a URL is created that represents the root node of the JSON object. To work with it, you need to create a "Ref" + +```javascript +var ref = new Firebase("https://tts-demo.firebaseio.com/"); +``` + + +### Writing Simple Data + +```javascript +var ref = new Firebase("https://tts-demo.firebaseio.com/"); + +ref.set({ + message: 'hello world' +}); +``` + +If you go to https://tts-demo.firebaseio.com/, you'll see that the data's been saved. + +The example above replaces the data completely. Instead, you can provide an object with a partial set of keys to update. + +```javascript +var ref = new Firebase("https://tts-demo.firebaseio.com/"); + +ref.set({ + className: 'JS', + weeks: 10 +}); + +ref.update({ + className: 'JS Application Development', + students: 15 +}); + +/* Ref is now +{ + className: 'JS Applications', + weeks: 10, + students: 15 +} +*/ + +``` + +### Reading Simple Data +Because Firebase is real-time, you don't request data in a discrete way like you do from a REST API. Instead, you listen for events on your data that signal when the data has been updated and run a callback when that happens. + +For example, we can run a callback function every time our JSON object is changed + +```javascript +ref.on("value", function(snapshot) { + console.log(snapshot.val()); +}) +``` + +**Note - Events are fired immediately for existing data.** + +### Child References +Most times, you don't want to listen to the whole JSON object, just a specific subsection. You can create a reference to a portion of your JSON object by using the reference's `child()` function. + +Let's say your data looks like this: + +```javascript +{ + class: 'JS Applications', + teacher: { + name: 'Shane', + computer: { + type: 'mac', + size: '15 inch' + } + } +} +``` + +You can read and listen for changes in just the `teacher` object by creating a child reference like this: + +```javascript +var ref = new Firebase("https://tts-demo.firebaseio.com/"); +var teacher = ref.child('teacher'); +teacher.on('value', function(v){/*... */}) +``` + +Child paths can be nested as deeply as you'd like. + +```javascript +var ref = new Firebase("https://tts-demo.firebaseio.com/"); +var ShanesComputer = ref.child('teacher/computer'); +``` + + +## Firebase with React +Let's add Firebase data to a React component. Let's start with a simple controlled component. + +```javascript +import React from 'react'; +import ReactDOM from 'react-dom'; +import classNames from 'classnames'; + +class MessageApp extends React.Component { + constructor() { + super(); + this.state = { + inputValue: '' + } + } + + _handleChange(event) { + this.setState({ + inputValue: event.target.value + }) + } + + render() { + + return ( +
    + +
    + ) + } +} + +var mountPoint = document.querySelector("#app"); +ReactDOM.render(,mountPoint) +``` + +#### Install Firebase +Next, we'll bring in Firebase via npm `npm install --save firebase`. We can now import firebase just like all of our other dependencies + +```javascript +import React from 'react'; +import ReactDOM from 'react-dom'; +import classNames from 'classnames'; + +//Import firebase! +import Firebase from 'firebase'; + +//... +``` + +#### Create a ref +For now, let's have our component create a firebase reference. + +```javascript + constructor() { + super(); + + this.state = { + inputValue: '' + } + + this.ref = new Firebase("https://tts-demo.firebaseio.com/"); + } +``` + +#### Get Data from Firebase +We can bring in data from Firebase in the `componentDidMount` event. + +```javascript +componentDidMount(){ + + //Arrow function so callback can use component's this.setState + ref.on("value", (snapshot) => { + this.setState({ + inputValue: snapshot.val() + }) + }) +} +``` +This creates a 1-way data binding from firebase to the component. That is, every time Firebase is updated, the component's state will be updated. + +#### Update data in Firebase +If we want updates to be saved to firebase, we'll have to update our reference object. + +```javascript +_handleChange(event) { + this.ref.update({inputValue: event.target.value}) +} +``` + +Notice that this.setState() isn't necessary! This is because your callback in componentDidMount will set update the component state for you. + +**Note - Your data is being updated in real time. Open another browser to the same local address and watch the magic happen** + +## Exercise 2: Binding data +Let's create a theme preview tool with React + +- Create a form with controlled text inputs for color and background +- Create a 'save' button +- Create a div (500px by 500px) with an h1 that reads 'This is a preview' +- When the 'save' button is clicked, save the two values currently in the inputs to a firebase reference +- Style the div to display the text color and background color stored in Firebase at all times +- Set up the inputs to contain the names of the text and background colors saved in firebase. + + +## Lists of data +One thing we haven't covered yet, is how to deal with arrays or lists with firebase. This is very similar to how we deal with other data, but with different events. We'll be using `ref.push(obj)` to write data and `child_added`, `child_removed` and `child_changed` events to read updated data + + +## Chat app +We'll start with our basic, one component, message app: + +```javascript +import React from 'react'; +import ReactDOM from 'react-dom'; +import classNames from 'classnames'; + +class MessageApp extends React.Component { + constructor() { + super(); + this.state = { + newMessageInput: '', + messages: [] + } + } + + _handleButton(event) { + var newMessage = this.refs.messageInput.value; + this.setState({ + messages: this.state.messages.concat(newMessage) + }) + } + + _handleChange(event) { + this.setState({ + newMessageInput: event.target.value + }) + } + + render() { + var messages = this.state.messages.map((message, i)=>{ + return
  • {message}
  • + }) + + return ( +
    +

    Slick

    + + +
      + {messages} +
    +
    + ) + } +} + +var mountPoint = document.querySelector("#app"); +ReactDOM.render(,mountPoint) +``` + +We're going to want to read and write the state.messages array from Firebase following the same steps are before: + +#### Import firebase +`import Firebase from 'firebase';` + +#### Create a reference to messages +```javascript +constructor() { + super(); + this.state = { + newMessageInput: '', + messages: ['hello', 'world'] + } + + this.messagesRef = new Firebase("https://tts-demo.firebaseio.com/messages"); +} +``` + +#### Get data in componentDidMount using 'child_added' event + +```javascript +componentDidMount(){ + this.messagesRef.on("child_added", (snapshot) => { + this.setState({ + messages: this.state.messages.concat(snapshot.val()) + }) + }) + } +``` + +#### Push new messages in the _buttonHandle function + +```javascript +_handleButton(event) { + this.messagesRef.push(this.refs.messageInput.value) +} +``` + +## Exercise 3 + Homework +Write a persistant chat app with React + Firebase. + +- Create a login page where the user enters their name +- Validate that the name is more than 1 character and show error otherwise +- Upon login show all previously written messages along with + - Username + - Message + - Time +- Let users enter new messages and show them in real time +- Read about firebase Authentication - https://www.firebase.com/docs/web/guide/user-auth.html +- Implement user authentication using email and password +- Style the app to your heart's content +- Deploy your app to firebase and send us a link in slack + diff --git a/lesson 999 - Next Steps.md b/lesson 999 - Next Steps.md new file mode 100644 index 0000000..6b978cb --- /dev/null +++ b/lesson 999 - Next Steps.md @@ -0,0 +1,42 @@ +## Next Steps + +# Next Steps + +### A list of resources for helping anyone on their coding journey + +## Tutorials and Books + +[Free Code Camp](https://www.freecodecamp.com/) - A 2000 hour course that takes you through each step of full-stack development (React material coming soon)
    +[React For Beginners](https://reactforbeginners.com/) - A famous intro to react from Wes Bos
    +[Code School's JS path](https://www.codeschool.com/learn/javascript) - An Excellent way to review and sharpen your JS skills
    +[ReactJS Fundamentals](http://www.reactjsprogram.com/) A project based, linear approach to learning React.js and the React.js ecosystem
    +[Egghead.io](https://egghead.io)- An excellent series of videos focusing on all things front-end.
    +[FrontEnd Masters](https://frontendmasters.com/) - Excellent lectures and examples of JS from beginner to advanced +[All of the TeamTreehouse JS videos](http://teamtreehouse.com/library/topic:javascript) - (you can add them to your dashboard and work through each independent of a track) +[NodeSchool.io](http://nodeschool.io/) - Though you're already familiar with it, NodeSchool is an excellent resource to continue sharpening your skills
    + + +## Challenges + +[Code Wars](http://www.codewars.com/) - is an excellent way to sharpen your skills. I try to spend at least 30 minutes a day working on problems.
    +[Code Combat](http://www.codecombat.com) - a fun and quirky way to work with basic JS or Python
    + + +##To get involved (and get noticed) + +[Trending on GitHub](https://github.com/trending) - a list of trending repos on GitHub
    +[Code for Charlotte](http://www.meetup.com/Code-For-Charlotte/) - you should already be involved here. +[Charlotte JS](http://www.meetup.com/CharlotteJS/) - hardcore JS with a great group of people +[Charlotte Front End Developers](http://www.meetup.com/Charlotte-Front-End-Developers/) - great topics concerning all things front-end + + +## Podcasts + +[JavaScript Air](http://javascriptair.com/) - RoundTable from many of the leading JS developers
    +[React Podcast](http://reactpodcast.com/) +[Code Newbie](http://www.codenewbie.org/podcast) - Awesome resource for new developers. (I’d recommend starting at the beginning) +[Reboot](http://rebootshow.fm/) - a Thoughtbot experiment that interviews people that transitioned from various careers into development +[Giant Robots Smashign into Other Robots](http://giantrobots.fm/) - Thoughtbot podcast dealing with dev, design, business, etc (usually has an interview) +[Developer Tea](https://developertea.com/) - short podcasts that deal with all various aspects of becoming a great developer +[The FrontSide](https://frontsidethepodcast.simplecast.fm/) - two guys talking about code and life +[Hansel Minutes](http://hanselminutes.com/) - Like NPR’s fresh air… just aimed at developers