master
Matt Huntington 8 years ago
commit 1fce93a165

@ -0,0 +1,134 @@
![In Rhythm](logo.gif)
# Using AJAX With Redux
## Lesson Objectives
1. Make an AJAX GET Request Using Fetch
1. Make an AJAX POST Request Using Fetch
1. Create a SET Reducer for the Store
1. Dispatch a SET action appropriately
1. Dispatch a ADD action appropriately
## Make an AJAX GET Request Using Fetch
In `js/index.js` make a test GET request:
```javascript
fetch('https://stupidcomments.herokuapp.com/comments').then(function(response){
response.json().then(function(data){
console.log(data);
});
});
```
## Make an AJAX POST Request Using Fetch
In `js/index.js` make a test POST request:
```javascript
fetch(
'https://stupidcomments.herokuapp.com/comments',
{
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
},
method: "POST",
body: JSON.stringify({ body:'again from react' })
}
).then(function(response){
response.json().then(function(data){
console.log(data);
});
});
```
**NOTE** When you're finished with this code, comment it out, so you don't keep creating new comments
## Create a SET Reducer for the Store
Our plan is the make a GET request to our API and then set the store to the response's values.
Create a SET Reducer in `js/store.js`:
```javascript
let comments = function(state = [], action){
switch(action.type){
case 'ADD':
return [...state, action.comment];
case 'SET':
return action.comments
default:
return state
}
}
```
## Dispatch a SET action appropriately
Import `js/store.js` into `js/components/commentslist.jsx`:
```javascript
import store from '../store.js';
```
Once our `js/components/commentslist.jsx` component mounts, make the approriate AJAX request and dispatch a SET action.
```javascript
componentDidMount(){
fetch('https://stupidcomments.herokuapp.com/comments').then(function(response){
response.json().then(function(data){
console.log(data);
});
});
}
```
Now dispatch a `SET` action:
```javascript
componentDidMount(){
fetch('https://stupidcomments.herokuapp.com/comments').then(function(response){
response.json().then(function(data){
store.dispatch({type:'SET', comments:data});
});
});
}
```
## Dispatch a ADD action appropriately
In `js/components/commentsform.jsx` alter the `handleSubmit` property to make an AJAX POST request:
```javascript
const mapDispatchToProps = function(dispatch){
return {
handleSubmit: function(comment){
fetch(
'https://stupidcomments.herokuapp.com/comments',
{
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
},
method: "POST",
body: JSON.stringify(comment)
}
).then(function(response){
response.json().then(function(data){
console.log(data);
});
});
}
}
}
```
We can see that `data` has a `body` property that we want to use in our dispatch in `js/components/commentsform.jsx`:
```javascript
response.json().then(function(data){
dispatch({type:'ADD', comment: data });
});
```

@ -0,0 +1,303 @@
![In Rhythm](logo.gif)
# Comments Component Build
This builds off of what was built by the end of [the Webpack Lesson](Webpack.md).
## Lesson Objectives
1. Create Comments component
1. Create CommentsList component
1. Create CommentsForm component
1. Display an array of comments
1. Make form add new comments
1. Create the ability to add new comments to the Comments component
1. Have the Comments form call the Comments component's addComment function
## Create Comments component
Create a directory for components:
```
mkdir js/components
```
Rename `mylib.js` to `comments.jsx` and move it in the `components` dir:
```
mv js/mylib.js js/components/comments.jsx
```
Create the Comments class in `js/components/comments.jsx`:
```javascript
import React from 'react';
class Comments extends React.Component {
render(){
return <h1>Comments Component</h1>
}
}
export default Comments;
```
Import the Comments component into `js/index.js`:
```javascript
import ReactDOM from 'react-dom';
import React from 'react';
import Comments from './components/comments.jsx';
ReactDOM.render(
<Comments></Comments>,
document.querySelector('main')
);
```
## Create CommentsList component
Create a separate file for the comments list:
```
touch js/components/commentslist.jsx
```
In `js/components/commentslist.jsx` create a basic component:
```javascript
import React from 'react';
class CommentsList extends React.Component {
render(){
return <ul>
<li>comments list</li>
</ul>
}
}
export default CommentsList;
```
Import CommentsList into `js/components/comments.js`:
```javascript
import React from 'react';
import CommentsList from './commentslist.jsx'
class Comments extends React.Component {
render(){
return <section>
<CommentsList></CommentsList>
</section>
}
}
export default Comments;
```
## Create CommentsForm component
Create `js/components/commentsform.jsx`:
```
touch js/components/commentsform.jsx
```
Write a basic component in `js/components/commentsform.jsx`:
```javascript
import React from 'react';
class CommentsForm extends React.Component {
render() {
return <form>
<input type="text" placeholder="author"/><br/>
<textarea placeholder="comment"></textarea><br/>
<input type="submit" value="Post Comment"/>
</form>
}
}
export default CommentsForm;
```
Import CommentsForm into `js/components/comments.js`:
```javascript
import React from 'react';
import CommentsList from './commentslist.jsx'
import CommentsForm from './commentsform.jsx'
class Comments extends React.Component {
render(){
return <section>
<CommentsList></CommentsList>
<CommentsForm></CommentsForm>
</section>
}
}
export default Comments;
```
## Display an array of comments
In `js/components/comments.jsx`, create a constructor in the Comments class that initializes an array of comments:
```javascript
constructor(props){
super(props);
this.state = {
comments: [
{
body:'this rox',
author:'bob'
},
{
body:'no, you rox',
author:'sally'
},
{
body:'we all rox',
author:'zagthor'
}
]
}
}
```
Now pass it off to the CommentsList component:
```javascript
<CommentsList comments={this.state.comments}/>
```
In `js/components/commentslist.jsx` loop through the `comments` prop and display the comments:
```javascript
import React from 'react';
class CommentsList extends React.Component {
render(){
return <ul>
{this.props.comments.map((comment, index) =>
<li key={index}>
{comment.author} says: "{comment.body}"
</li>
)}
</ul>
}
}
export default CommentsList;
```
## Create the ability to add new comments to the Comments component
In `js/components/comments.jsx` set the comments state property to an empty array:
```javascript
constructor(props){
super(props);
this.state = {
comments: []
}
}
```
Add the ability to add a new comment in `js/components/comments.jsx`
- you have to use `this.setState` or react won't know the state has changed and won't refresh the DOM
```javascript
addComment(comment){
this.state.comments.push(comment); //this alone won't notify React to update the DOM
this.setState({
comments: this.state.comments
});
}
```
Now bind the `addComment` function in the constructor for `js/components/comments.jsx`:
```javascript
constructor(props){
super(props);
this.state = {
comments: []
}
this.addComment = this.addComment.bind(this);
}
```
## Have the CommentsForm call the Comments component's addComment function
In `js/components/comments.jsx` create a property on the CommentsForm element called `handleSubmit` and pass it `this.addComment`:
```javascript
render(){
return <section>
<CommentsList comments={this.state.comments}></CommentsList>
<CommentsForm handleSubmit={this.addComment}></CommentsForm>
</section>
}
```
In `js/components/commentsform.jsx`, create a handleSubmit function in the `CommentsForm` class definition:
```javascript
handleSubmit(event){
event.preventDefault();
console.log('posting comment');
}
```
Don't forget to create a constructor that binds handleSubmit in `js/components/commentsform.jsx`:
```javascript
constructor(props){
super(props);
this.handleSubmit = this.handleSubmit.bind(this);
}
```
Now call it on form submit in `js/components/commentsform.jsx`:
```javascript
return <form onSubmit={this.handleSubmit}>
<input type="text" placeholder="author"/><br/>
<textarea placeholder="comment"></textarea><br/>
<input type="submit" value="Post Comment"/>
</form>
```
Create references to the comment textarea and author input element in `js/components/commentsform.jsx`:
```html
<input ref="author" type="text" placeholder="author"/><br/>
<textarea ref="body" placeholder="comment"></textarea><br/>
```
In the `handleSubmit` function of `js/components/commentsform.jsx`, log this element's value:
```javascript
handleSubmit(event){
event.preventDefault();
console.log(this.refs.author.value);
console.log(this.refs.body.value);
}
```
Now call the `handleSubmit` function that was passed into the CommentsForm component by the Comments component:
```javascript
handleSubmit(event){
event.preventDefault();
this.props.handleSubmit({
body: this.refs.body.value,
author: this.refs.author.value
});
}
```

@ -0,0 +1,160 @@
![In Rhythm](logo.gif)
# Integrate Comments Component With Redux
## Lesson Objectives
1. Install Redux
1. Create the Store
1. Make CommentsList Subscribe to the Store
1. Make CommentsForm Dispatch Actions
1. When an Action Occurs, make CommentsList Update State
1. Remove Unnecessary Code
## Install Redux
```
npm install redux --save-dev
```
## Create the Store
Create `js/store.js`:
```
touch js/store.js
```
Write a basic store that handles an `ADD` action and a `default`:
```javascript
import { createStore } from 'redux'
let comments = function(state = [], action){
switch(action.type){
case 'ADD':
return [...state, action.comment];
default:
return state
}
}
let store = createStore(comments);
export default store;
```
## Make CommentsList Subscribe to the Store
In `js/components/commentslist.jsx`, import the store:
```javascript
import store from '../store.js';
```
Once the component mounts, subscribe to the store:
```javascript
componentDidMount(){
store.subscribe(function(){
console.log(store.getState())
});
}
```
## Make CommentsForm Dispatch Actions
In `js/components/commentsform.jsx`, import the store:
```javascript
import store from '../store.js';
```
In the handleSubmit function, dispatch an `ADD` action:
```javascript
handleSubmit(event){
event.preventDefault();
this.props.handleSubmit({
body: this.refs.body.value,
author: this.refs.author.value
});
store.dispatch({
type:'ADD',
comment: {
body: this.refs.body.value,
author: this.refs.author.value
}
});
}
```
## When an Action Occurs, make CommentsList Update State
Set up a state property in `js/components/commentslist.jsx` for comments:
```javascript
constructor(props){
super(props)
this.state = {
comments: []
}
}
```
when an action occurs, set the state property (we'll need to use an arrow function for proper bind of `this`):
```javascript
componentDidMount(){
store.subscribe(() => {
this.setState({
comments: store.getState()
});
});
}
```
Now use that state variable instead of the `comments` prop:
```javascript
render(){
return <ul>
{this.state.comments.map((comment, index) =>
<li key={index}>
{comment.author} says: "{comment.body}"
</li>
)}
</ul>
}
```
## Remove Unnecessary Code
- We no long need to store anything in `js/components/comments.jsx`
- We also don't need to pass anything to child components:
```javascript
class Comments extends React.Component {
render(){
return <section>
<CommentsList></CommentsList>
<CommentsForm></CommentsForm>
</section>
}
}
```
`js/components/commentsform.jsx` no long needs to call `this.props.handleSubmit`:
```javascript
handleSubmit(event){
event.preventDefault();
store.dispatch({
type:'ADD',
comment: {
body: this.refs.body.value,
author: this.refs.author.value
}
});
}
```

@ -0,0 +1,117 @@
![In Rhythm](logo.gif)
# Integrate Redux Into Comments Part 2
The last section works, but there are some optimizations we can make
## Lesson Objectives
1. Install `react-redux`
1. Map Redux State To The CommentsList Component
1. Map a Dispatch ADD Action to a CommentsForm Component property
## Install `react-redux`
```
npm install react-redux --save-dev
```
Import `react-redux`'s `Provider` module in `js/index.js`:
```javascript
import { Provider } from 'react-redux';
```
In `js/index.js` wrap `<Comments></Comments>` in a `<Provider></Provider>` component to make redux available to the `Comments` component. Also set the `store` property to the `store` we import from `./store.js`:
```javascript
import store from './store.js';
ReactDOM.render(
<Provider store={store}>
<Comments></Comments>
</Provider>,
document.querySelector('main')
);
```
## Map Redux State To The CommentsList Component
In `js/components/commentslist.jsx`, import `connect` from `react-redux`:
```javascript
import { connect } from 'react-redux';
```
In `js/components/commentslist.jsx` create a function that will map redux `state` to component properties:
```javascript
const mapStateToProps = function(state){
return {
comments: state
}
}
```
In `js/components/commentslist.jsx` connect the mapper with the component:
```javascript
const VisibleCommentsList = connect(
mapStateToProps
)(CommentsList);
```
In `js/components/commentslist.jsx`, export `VisibleCommentsList`:
```javascript
export default VisibleCommentsList;
```
You can now remove the `constructor`/`componentDidMount` functions and change `this.state.comments.map` to `this.props.comments.map` show we back to using props instead of component state:
## Map a Dispatch ADD Action to a CommentsForm Component property
Import `connect` component from `react-redux` into `js/components/commentsForm.jsx`:
```javascript
import { connect } from 'react-redux';
```
Now create a function that will map a dispatch to a property in `js/components/commentsForm.jsx`:
```javascript
const mapDispatchToProps = function(dispatch){
return {
handleSubmit: function(comment){
dispatch({type:'ADD', comment: comment });
}
}
}
```
Connect the mapper to the `CommentsForm` component in `js/components/commentsForm.jsx`:
```javascript
const VisibleCommentsForm = connect(
null, //normally the mapStateToProps function
mapDispatchToProps
)(CommentsForm)
```
Export the `VisibleCommentsForm` component:
```javascript
export default VisibleCommentsForm;
```
Refactor `handleSubmit` to this the `handleSubmit` component prop:
```javascript
handleSubmit(event){
event.preventDefault();
this.props.handleSubmit({
body: this.refs.body.value,
author: this.refs.author.value
});
}
```

723
ES6.md

@ -0,0 +1,723 @@
![In Rhythm](logo.gif)
# ES6 - The Future Is Now! (Sort of)
## Lesson Objectives
1. What is ES6
1. strict mode
1. understanding MDN
1. polyfills and shims
1. babel/transpiling
1. IFFE
1. Block level scoping with let
1. const
1. arrow functions
1. Classes
1. for...of
1. default value setting
1. Array.isArray()
1. argument object
1. spread and rest operators
1. Template Literals
1. Object literal extensions
1. Destructuring
1. swap (desconstucturing method)
<!-- TODO: -->
1. symbols
1. helper functions (trunc, entries, values, keys)
1. unicode
1. Maps/Sets, WeakMaps/WeakSets
1. proxies
1. promises
1. generators
## What is ES6
ECMAScript is the standard version of JavaScript. ECMA stands for European Computer Manufacturers Association. ES5 became standard in 2009. ES6 (or ES2015), became standard in 2015. But just because it is made standard, it doesn't mean that all browsers/environments are ready/compliant.
## Strict Mode
Adding 'use strict' to the top of your code, (see Babel screenshot) will let you opt in to some newer features of JS! [More info](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Strict_mode)
## understanding MDN
- Lets you know which methods/syntaxes are standard, experimental, depreciated, when things were added and more including shims/polyfills.
- [forEach on MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/forEach)
- Quickly see if a method is standard[no notation], experimental[flask], depreciated (removed from standards, may be removed)[thumbs down], or obsolete (likely removed altogether in newer environments)[trash can]
![Screenshot left bar, objects](https://i.imgur.com/nSqSXwf.png)
- See more information about when the method was defined implemented:
![Screenshot- forEach Specifications section](https://i.imgur.com/7bPC29H.png)
## Polyfills/Shims
Some people call them polyfills, some call them shims; either way: It is code that is a fallback that provides the functionality when the expected functionality is not available (because old browser, etc. ). Many entries in MDN have polyfills. This is also a great way to look at how the ECMAScript standard code is written (a lot of examples are directly from the official ECMAScript docs)
An example Polyfill:
![Screenshot- forEach polfill section](https://i.imgur.com/e0G8ZCB.png)
## babel/transpiling
Now! But it depends where. Node.js supports most/nearly all new things. [Chrome, Firefox, Edge, and Safari have been keeping up well](http://caniuse.com/#search=es6). But new features are being added and tested. To be sure that code will run across many platforms (never forget the people who still use IE8), many people have come to rely on transpilers/compilers. Transpilers/Compilers take 'dialects' of standard code (incuding ES6, coffeescript, typescript and more) and convert the code for you. A popular one for ES6 is [Babel](https://babeljs.io/), they have both repl (Read, Evaluate, Print, Loop) and an npm module/gem.
![babel repl](https://i.imgur.com/SKLMkIU.png)
## IIFE
Normally, variable declarations, are "hoisted" up to the top of whatever function they are declared in (or global if no function exists). This can lead to some weird moments:
```JavaScript
var a = 2;
if(true){
var a = 4;
}
console.log(a); //in many programming languages, this would be 2
```
and a famous interview question:
```JavaScript
for(var i=0; i<5; i++){
setTimeout(function(){
console.log(i) //you'd expect 0,1,2,3,4
},500 * i);
}
```
IIFE - Immediately Invoked Function Expression - often used to create a block of scope. This is not an ES6 thing, but rather an example of an old way to get block scoping.
```JavaScript
var a = 2;
(function IIFE(){
var a = 4;
console.log ('Inside the IFFE, the value of a is', a ); //"Inside the IFFE, the value of a is 4"
})();
console.log ( 'Outside the IFFE, the value of a is', a ); //"Outside the IFFE, the value of a is 2"
```
And now the loop with setTimeout:
```JavaScript
for(var i=0; i<5; i++){
(function(i){
setTimeout(function(){
console.log(i)
},500 * i);
})(i)
}
```
## Block Scoping with let
A new way to get block level scoping is with the keyword let, and the use of `{}` as in any `{}`, not just tied to a function! Note: `let` is NOT meant to completely replace `var`!
```JavaScript
var a = 2
{
let a = 4
console.log( 'the value of b inside the `{}` is', a); //"block level scope"
}
console.log ('the value of b outside of the `{}` is', a) //"global scope"
```
And now the loop with setTimeout:
```JavaScript
for(let i=0; i<5; i++){
setTimeout(function(){
console.log(i) //you'd expect 0,1,2,3,4
},500 * i);
}
console.log(i); //notice i is not defined outside of the loop
```
## Const
Another new way to declare a variable. This will block the value from being reassigned.
```JavaScript
const pi = 3.14;
pi = "pie" //TypeError: Assignment to constant variable.
const whatsForLunch = [ "Nuts", "Coffee" ]
whatsForLunch.push( "Yogurt" ) //you can still call object methods that alter the variable
console.log( whatsForLunch)
whatsForLunch.shift(); //you can still call object methods that alter the variable
console.log( whatsForLunch )
whatsForLunch = ["salad"]; //TypeError: Assignment to constant variable.
```
## Arrow Functions
A new way to write a function expression (arrow functions are always anonymous functions), with fun shortcuts:
### Shorthands
Basic:
```JavaScript
var basicES5 = function(){
return 'oh hai';
}
//take out the keyword 'function' and add in '=>'
var basicES6 = () => {
return 'oh hai'
}
```
If the body of the function is just one expression that gets returned, we can remove the `{}` and ES6 knows to return whatever comes after the `=>`
```JavaScript
var basicES6 = () => 'oh hai'
```
Multiple arguments:
```JavaScript
//ES5 - Multiple arguments
var sumES5 = function (a, b){
return a+b;
}
console.log('ES5 sum:',sumES5(5,5));
//ES6 - Multiple arguments
var sumES6 = ( a, b ) => a + b;
console.log('ES6 sum:', sumES6(6,6));
```
If we only have one argument to the function, we can leave out the `()`
```JavaScript
//ES5 - one argument
var squareES5 = function (c){
return c*c;
}
console.log('ES5 square:', squareES5(5));
//ES6 - one argument
var squareES6 = c => c*c
console.log('ES6 square:',squareES6(6));
```
### Binding
Here is an example of the arrow function binding this
```JavaScript
// Create constructor function, inputs name, has default friend values
function Person ( name , friends = ["Charlie", "Dennis", "Ron", "Sweet Dee", "Frank"]){
this.name = name;
this.friends = friends;
//Add four methods:
// The first, `secret Admirer`, `this.name` is undefined in the forEach function
this.secretAdmirer = function (){
this.friends.forEach(function ( f ){
console.log( this.name + " sends flowers to " + f );
});
}
//The second one is the way we got around the issue of `this` - which was to set the desired `this` to a variable called `that` or `self` or something similar:
this.giveOldSchoolLove = function (){
var self = this;
this.friends.forEach(function ( f ){
console.log( self.name + " likes " + f );
});
}
// we could also use .bind()
this.giveBindingAffection = function (){
this.friends.forEach(function ( f ){
console.log( this.name + " makes friendship bracelets for " + f )
}.bind(this));
}
//Finally, by using the arrow function, `this` is already bound:
this.giveNewSchoolLove = function (){
this.friends.forEach(f => console.log( this.name + " hearts " + f ));
}
}
//See examples
k = new Person ( "Matt" );
console.log( 'Secret Admirer:' );
k.secretAdmirer();
console.log( 'Show old school love:' );
k.giveOldSchoolLove();
console.log( 'Show new school love:' );
k.giveNewSchoolLove();
```
## Support for Classes
```JavaScript
class Cat {
constructor(name) {
this.name = name;
}
makesNoises() {
return (this.name + 'meows');
}
purrs(){
return (this.name + 'purrs');
}
}
class Lion extends Cat {
makesNoises() {
return (this.name + 'roars!');
}
eatHuman(){
return 'yum';
}
}
var myCat = new Cat("Kitty");
console.log(myCat.makesNoises());
console.log(myCat.purrs());
var myLion = new Lion("Simba");
console.log(myLion.makesNoises());
console.log(myLion.purrs());
console.log(myLion.eatHuman());
```
## for...of
Until now, the best way to loop through an array was either:
```JavaScript
var array = [1,4,6];
for(var i =0; i < array.length; i++){
console.log(array[i]);
}
```
Or:
```JavaScript
var array = [1,4,6];
array.forEach(function(element){
console.log(element);
});
```
But now we can do:
```JavaScript
var array = [1,4,6];
for(let element of array){
console.log(element);
}
```
## Default values
When creating a constructor and you wanted a default value, you previously had to write something like this:
```JavaScript
function Beverage( type ){
this.type = type || "water";
}
var breakfast = new Beverage();
var breakfast2 = new Beverage( 'beer' );
console.log ( breakfast );
console.log ( breakfast2 );
```
Now you can do this in ES6
```JavaScript
function Beverage ( type = 'sparkling water' ){
this.type = type;
}
var breakfast = new Beverage();
var breakfast2 = new Beverage( 'rocket fuel' );
console.log ( breakfast );
console.log ( breakfast2 );
```
## Array.isArray()
If you have tried to confirm if something is an array with ES5, you may have found it frustrating:
```JavaScript
var arr = [1,2,3];
console.log(typeof arr); //'object'
```
You could do
```JavaScript
arr instanceof Array; // true
```
But now there is a new method!
```JavaScript
Array.isArray(arr); //true
```
## Argument Object
This isn't an ES6 thing, but should help expand your knowledge of arguments in JS.
The arguments object is an array-like object (but not fully an array, so you cannot always call array methods on it). It allows for a lot of flexibility in the number of arguments a function can take:
```JavaScript
function sum (){
var sum = 0;
for(var i = 0; i < arguments.length; i++ ){
sum += arguments[i];
}
return sum;
}
console.log( sum(1,2,3,4) ); //10
```
## Spread and Rest Operators
### Spread operator:
Spread Operator will take an array, and convert each element into its own value. It "spreads" the elements out into values
Let's look at `Math.max()` which takes any number of arguments and finds the maximum value
```JavaScript
//Standard syntax
console.log(Math.max(1,5,-6)); // 5
```
- But what if you have an array of values?
- Converting each to a variable and then adding them as arguments is a pain, until now:
```JavaScript
var z = [1,5,-2,8,-9,17,-22];
console.log(Math.max(...z)); // 17
```
### Rest operator:
The rest operator gathers many values into an array. It's basically the opposite of spread.
```JavaScript
function returnOnlyNums(...arrayParam){
var nums = arrayParam.filter(arg => typeof arg === 'number');
return nums;
}
console.log( returnOnlyNums(44, false, 'pizza', 45, {season: "winter"}, [1,2,3,4,5,], 2, 9) ); // [ 44, 45, 2, 9 ]
```
## Template Literals (String Interpolation)
Template literals allow you to insert variables into strings with out having to use `+`
The old way:
```JavaScript
var name = "Matt"
console.log ('Hello '+ name);
```
Now we can do this:
```JavaScript
var name = "Matt"
console.log (`Hello ${name}.`);
```
You can even evaluate JavaScript within the Template Literal:
```JavaScript
var name = "Matt";
function yell(value){
return value.toUpperCase();
}
console.log (`Hello ${yell(`${name}`)}!`);
```
Multiple lines used to suck:
```JavaScript
var adjective = 'awesome'
var template = 'I wrote a haiku\n'+
'This is so very ' + adjective + '\n'+
'Now I am finished';
console.log(template);
```
Now they're easy!
```JavaScript
var adjective = 'awesome';
var template = `I wrote a haiku
This is so very ${adjective}
Now I am finished`;
console.log(template);
```
## Object literal upgrades
Instead of:
```JavaScript
var a = 8;
var b = 9;
var c = 10;
var es5obj = {
a:a,
b:b,
c:c,
d : function (){
console.log(this.a, this.b, this.c);
}
}
es5obj.d();
```
Now do:
```JavaScript
var a = 8;
var b = 9;
var c = 10;
var es6obj = {
a,
b,
c,
d(){
console.log(this.a, this.b, this.c);
}
}
es6obj.d();
```
## Destructuring
Destructuring pulls variables out of their "structure" (array or object)
### Array Destructuring
You can assign values an array to variables easily:
```JavaScript
var a, b;
[a,b] = [10,12]
console.log(a);
console.log(b);
```
You can also declare in the same line as assignment:
```JavaScript
var [a,b] = [10,12]
console.log(a);
console.log(b);
```
You can ignore certain values:
```JavaScript
var a, b;
[a,,b] = [1,2,3,4];
console.log(a);
console.log(b);
```
You can also use a rest operator to gather variables into an array after a certain point:
```JavaScript
var a, b, rest;
[a,b,...rest] = [10, 20, 30, 40, 50];
console.log(a);
console.log(b);
console.log(rest);
```
You can set defaults as well:
```JavaScript
var a, b;
[a=5, b=7] = [1];
console.log(a); // 1
console.log(b); // 7
```
### Object Destructuring
Pull variables out of an object
```JavaScript
var p, q;
{p, q} = {p: 42, q: true};
console.log(p); // 42
console.log(q); // true
```
You can also change the names of the variables:
```JavaScript
var o = {p: 42, q: true};
var {p: foo, q: bar} = o;
console.log(foo); // 42
console.log(bar); // true
```
You can also do default values:
```JavaScript
var {a = 10, b = 5} = {a: 3};
console.log(a); // 3
console.log(b); // 5
```
Use this for default options arguments:
```JavaScript
function drawES2015Chart({size = 'big', cords = {x: 0, y: 0}, radius = 25} = {}) {
console.log(size, cords, radius);
}
drawES2015Chart({
cords: {x: 18, y: 30},
radius: 30
});
```
You can pull values from a function argument that's an object:
```JavaScript
var user = {
id: 42,
displayName: 'jdoe',
fullName: {
firstName: 'John',
lastName: 'Doe'
}
};
function userId({id}) {
return id;
}
console.log('userId: ' + userId(user)); // "userId: 42"
```
If you have a property name which is not a valid variable name, you can reassign it:
```JavaScript
const foo = { 'fizz-buzz': true }
const { 'fizz-buzz': fizzBuzz } = foo
console.log(fizzBuzz);
```
Lastly, you can compute a variable name:
```JavaScript
let key = 'z';
let {[key]: foo} = {z: 'bar'};
console.log(foo); // "bar"
```
## Swap values: File under `Destructuring Assignment`
If you wanted to swap the value of x and y with es5, you had to do
```JavaScript
var x = true;
var y = false;
var temp;
temp = x;
x = y;
y = temp;
console.log(x,y);
```
The new way will return x and y to original values in this case
```JavaScript
var x = true;
var y = false;
[x,y] = [y,x];
console.log(x,y);
```
<details><summary>Note</summary>
The reason this is special and new is because we have to
remember that array values are normally passed by reference.
It is also unusual to have an array that is not assigned to a variable
```JavaScript
// Pass by reference
var a = 1;
var b = 2;
var originalArray = [a,b];
console.log('is `a` equal to orginalArray[0]:', a === originalArray[0]);//true
var newArray = originalArray;
//will reverse BOTH arrays (because it is actually two references to the same array)
newArray.reverse()
console.log('This is newArray.reverse():', newArray)
console.log('This is originalArray after newArray has been reversed', originalArray)
console.log('is `a` equal to orginalArray[0]:', a === originalArray[0]);//false
```
To make a duplicate array that is not passed by reference, you would have to do something like:
```JavaScript
var a = 1;
var b = 2;
var anotherOriginalArray = [a,b];
console.log('is `a` equal to anotherOrginalArray[0]:', a === anotherOriginalArray[0]);//true
var trueNewArray = anotherOriginalArray.map(function(e){
return e;
});
console.log('this is trueNewArray', trueNewArray);
trueNewArray.reverse();
console.log('\nThis is trueNewArray.reverse():', trueNewArray);
console.log('This is anotherOriginalArray after trueNewArray has been reversed', anotherOriginalArray);
console.log('is `a` equal to anotherOriginalArray[0]:', anotherOriginalArray[0] === a); //true
```
</details>

@ -0,0 +1,15 @@
![In Rhythm](logo.gif)
# Training Layout
1. Day 1: [Intro To ES6](/ES6.md)
1. Day 1: [Essential Tools (Atom/JSX + Babel.io)](/Tools.md)
1. Day 1/2: [React Basics](/ReactBasics.md)
1. Day 2: [Essential Tools (React Dev Tools)](/Tools.md)
1. Day 2: [Webpack](/Webpack.md)
1. Day 3: [Comments Component Build](/Comments.md)
1. Day 3: [Intro To Redux](/Redux.md)
1. Day 3: [Integrate Redux Into Comments](/CommentsRedux.md)
1. Day 3: [Integrate Redux Into Comments Part 2](/CommentsRedux2.md)
1. Day 3: [AJAX And Redux](/AJAXRedux.md)
1. Day 3: [React Router](/ReactRouter.md)

File diff suppressed because it is too large Load Diff

@ -0,0 +1,252 @@
![In Rhythm](logo.gif)
# React router
## Lesson Objectives
1. Basic Install
1. Get React Working
1. Install React Router
1. Create a Link To a Route
1. Create a Router Handler
1. Create a Parameterized Router Handler
## Basic Install
```
npm init
touch .gitignore
```
In `.gitignore` add
```
node_modules
```
Install basic packages:
```
npm install babel-core babel-loader babel-preset-es2015 babel-preset-react react react-dom webpack webpack-dev-server --save-dev
```
Create `webpack.config.js`
```
touch webpack.config.js
```
And set up a standard config:
```javascript
module.exports = {
entry: './js/index.js',
output: {
filename: 'dist/bundle.js'
},
module: {
rules: [
{
test: /\.(js|jsx)$/,
use: {
loader: 'babel-loader',
options: {
presets: ["es2015", "react"]
}
}
}
]
}
};
```
In `package.json`, tell it to use webpack as a build command:
```javascript
"scripts": {
"build": "webpack-dev-server --open"
},
```
## Get React Working
Create index.html:
```
touch index.html
```
Write basic HTML setup code:
```html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
</head>
<body>
<h1>Stuff</h1>
</body>
</html>
```
Create a `js` dir and a `js/index.js` file
```
mkdir js
touch js/index.js
```
In `js/index.js` write some basic react code:
```javascript
import React from 'react';
import ReactDOM from 'react-dom';
ReactDOM.render(
<h2>Matt is amazing</h2>,
document.querySelector('main')
);
```
In `index.html` include the soon-to-be compiled js and a `<main></main>` tag for React:
```html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
</head>
<body>
<h1>Stuff</h1>
<main></main>
<script src="/dist/bundle.js" charset="utf-8"></script>
</body>
</html>
```
Build and run:
```
npm run build
```
## Install React Router
Install the `react-router-dom` package
```
npm install react-router-dom --save-dev
```
Import various components in `js/index.js`:
```javascript
import {
BrowserRouter as Router,
Route,
Link
} from 'react-router-dom'
```
In `js/index.js`, wrap your base tag in a `<Router></Router>` component:
```javascript
ReactDOM.render(
<Router>
<h2>Matt is amazing</h2>
</Router>,
document.querySelector('main')
);
```
## Create a Link To a Route
In `js/index.js` create `<Link></Link>` components:
```javascript
ReactDOM.render(
<Router>
<ul>
<li>
<Link to="/about">About</Link>
</li>
</ul>
</Router>,
document.querySelector('main')
);
```
## Create a Router Handler
In `js/index.js` create a component to show for the `/about` route:
```javascript
class About extends React.Component{
render(){
return <h1>About</h1>
}
}
```
In `js/index.js` create a handler that will place that component when the url is correct:
```javascript
ReactDOM.render(
<Router>
<div>
<ul>
<li>
<Link to="/about">About</Link>
</li>
</ul>
<Route path="/about" component={About}/>
</div>
</Router>,
document.querySelector('main')
);
```
## Create a Parameterized Router Handler
In `js/index.js`, create `Link` to `/topics/news`:
```html
<ul>
<li>
<Link to="/about">About</Link>
</li>
<li>
<Link to="/topics/news">Topics</Link>
</li>
</ul>
```
In `js/index.js`, create a route handler that handles `/topics/:topicname`, where `:topicname` is url param that can be anything:
```html
<div>
<ul>
<li>
<Link to="/about">About</Link>
</li>
<li>
<Link to="/topics/news">Topics</Link>
</li>
</ul>
<Route path="/about" component={About}/>
<Route path="/topics/:topicname" component={Topics}/>
</div>
```
In `js/index.js`, create the `Topics` component that will be placed when the url is appropriate:
```javascript
class Topics extends React.Component{
render(){
return <h1>Topics: {this.props.match.params.topicname}</h1>
}
}
```

@ -0,0 +1,205 @@
![In Rhythm](logo.gif)
# Intro to Redux
## Lesson Objectives
1. Describe Redux
1. Install Redux
1. Create a reducer
1. Create a subscriber
1. Dispatch some actions
1. Move the store to a separate file
## Describe Redux
- Redux acts as a third party that just deals with data so that the "state" of a model (e.g. a list of comments) doesn't have to be constantly passed around between react components
- Redux works on the publisher/subscriber model
- a subscriber subscribes to Redux
- any subscribers to Redux receive notification when Redux's data changes
- the subscribers can then do what they want with the new "state" of Redux
## Install Redux
Initialize the directory:
```
npm init
```
Create a main JS file:
```
touch index.js
```
Install Webpack:
```
npm install webpack --save-dev
```
Install Redux:
```
npm install redux --save-dev
```
Create a config for Webpack:
```
touch webpack.config.js
```
Add appropriate config code:
```javascript
module.exports = {
entry: './index.js',
output: {
filename: 'bundle.js'
}
};
```
Set up NPM to run Webpack:
```javascript
"scripts": {
"build": "webpack"
},
```
Have `index.js` import `createStore` from `redux`
```javascript
import { createStore } from 'redux';
console.log(createStore);
```
Test that import works:
```
npm run build
```
## Create a reducer
A reducer will take an action and tell Redux how to alter its state. For now, write one in `index.js`
```javascript
import { createStore } from 'redux';
const comments = function(state = [], action){ //this function must take these params
switch(action.type){ //action must be an object that has a "type" property
case 'ADD': //if the type of action is "ADD"
return [...state, action.comment]; //return a copy of Redux's current state with the added comment
default: //always have a default that returns the current state
return state
}
}
//now create a data store based on the custom reducer
const store = createStore(comments);
```
## Create a subscriber
- Now let's create a subscriber in `index.js` that will be notified when our data store changes
- In the real world version of this example, this would probably be an HTML list that would update each time a new comment is made
```javascript
//subscriber (e.g. an HTML list)
store.subscribe(function(){
console.log(store.getState()); //for now just log what's in the store
});
```
## Dispatch some actions
- In `index.js`, let's dispatch some actions, telling Redux how to change state:
- In the real world version of this example, this would probably be a user filling out an HTML form and submitting it
```javascript
//publisher (e.g. an HTML form)
store.dispatch({
type:'ADD',
comment: {
body:'this rox',
author:'bob'
}
});
store.dispatch({
type:'ADD',
comment: {
body:'no, you rox',
author:'sally'
}
});
store.dispatch({
type:'ADD',
comment: {
body:'we all rox',
author:'zagthor'
}
});
```
## Move the store to a separate file
We want our data store in a separate file from our view logic
```
touch store.js
```
In `store.js`:
```javascript
import { createStore } from 'redux':
const comments = function(state = [], action){
switch(action.type){
case 'ADD':
return [...state, action.comment];
default:
return state
}
}
export default createStore(comments);
```
Import the store in `index.js`:
```javascript
import store from './store.js';
//subscriber (e.g. an HTML list)
store.subscribe(function(){
console.log(store.getState())
});
//publisher (e.g. an HTML form)
store.dispatch({
type:'ADD',
comment: {
body:'this rox',
author:'bob'
}
});
store.dispatch({
type:'ADD',
comment: {
body:'no, you rox',
author:'sally'
}
});
store.dispatch({
type:'ADD',
comment: {
body:'we all rox',
author:'zagthor'
}
});
```

@ -0,0 +1,13 @@
# Summary
* [Intro To ES6](/ES6.md)
* [Essential Tools (Atom/JSX + Babel.io)](/Tools.md)
* [React Basics](/ReactBasics.md)
* [Essential Tools (React Dev Tools)](/Tools.md)
* [Webpack](/Webpack.md)
* [Comments Component Build](/Comments.md)
* [Intro To Redux](/Redux.md)
* [Integrate Redux Into Comments](/CommentsRedux.md)
* [Integrate Redux Into Comments Part 2](/CommentsRedux2.md)
* [AJAX And Redux](/AJAXRedux.md)
* [React Router](/ReactRouter.md)

@ -0,0 +1,44 @@
![In Rhythm](logo.gif)
# Tools
## Lesson Objectives
1. Make Atom recognize JSX
1. Transpile ES2015 to ES5 Using Babel.io
1. Debug React Using React Dev Tools
## Make Atom recognize JSX
- By default, text editors like Atom don't recognize JSX code
- Atom allows us to install packages to enhance it
To Install from Atom:
1. Go to `Atom->Preferences`
1. Click `+ Install`
1. Search for `"react"`
1. Click `Install`
To Install from Terminal:
```
apm install react
```
You might need to do `Atom->Install Shell Commands`
## Transpile ES2015 to ES5 Using Babel.io
- Babel is an NPM package that converts ES2015 to ES5
- See what it does at: https://babeljs.io/repl/
- You can run it from the command line, but it's more common to use it as a plug-in to Webpack
## Debug React Using React Dev Tools
The [React dev tools](https://chrome.google.com/webstore/detail/react-developer-tools/fmkadmapgofadopljbjfkapdkoienihi?hl=en-US) allow you to inspect elements and see their properties, etc.
![react dev tools](https://lh3.googleusercontent.com/GjX6Q3_FVJfc0DqE2wiPKkgOfth6otzV-D7GV-wB6sH5_t1oodMaHOBLsYOLeydb85bKWu6X=s1280-h800-e365-rw)
- Follow [this link](https://chrome.google.com/webstore/detail/react-developer-tools/fmkadmapgofadopljbjfkapdkoienihi?hl=en-US) and click "Add To Chrome"
- You may need to refresh/restart chrome

@ -0,0 +1,339 @@
![In Rhythm](logo.gif)
# Webpack
- Webpack assembles your code and uses plug-ins to add additional features
- The only thing it does by itself is deal with ES2015 import/export statements
## Lesson Objectives
1. Install/Run Webpack
1. Create default export
1. Create a named export
1. Import only certain exports of file
1. Run webpack with NPM
1. Run webpack with Babel
1. Run webpack with JSX
1. Run webpack dev server
## Install/Run Webpack
```
npm init
npm install webpack --save-dev
```
Create a test file:
```
mkdir js
touch js/index.js
```
Add basic log to `index.js`:
```javascript
console.log('hi');
```
Create a `dist` folder:
```
mkdir dist
```
We can now run:
```
./node_modules/.bin/webpack js/index.js dist/bundle.js
```
Create a basic HTML file (`index.html`):
```html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
<script src="dist/bundle.js" charset="utf-8"></script>
</head>
<body>
</body>
</html>
```
Run it in the browser:
```
open index.html
```
## Create default export
Create a fake library (`js/mylib.js`)
```javascript
const myFunc = function(){
console.log('included!');
}
export default myFunc;
```
include it in `js/index.js`
```javascript
import defaultImport from './mylib.js';
defaultImport();
```
## Create a named export
Create the export in `js/mylib.js`:
```javascript
export const myFunc2 = function(){
console.log('also included');
}
```
**NOTE** The export can be defined when the export is created. This can happen for default and named exports
Import the function in `js/index.js`:
```javascript
import defaultImport, {myFunc2 as renamedExport} from './mylib.js';
defaultImport();
renamedExport();
```
If you don't want to rename the import in `js/index.js`:
```javascript
import defaultImport, {myFunc2} from './mylib.js';
defaultImport();
myFunc2();
```
We can of course set exports to variables in `js/mylib.js`:
```javascript
const savedFunc = function(){
console.log('also included');
}
export {savedFunc as myFunc2}
```
If the variable name is the same as the export name:
```javascript
const myFunc2 = function(){
console.log('also included');
}
export {myFunc2}
```
## Import only certain exports of file
You can have multiple named exports in `js/mylib.js`:
```javascript
const unnecessary = function(){
console.log('unnecessary');
}
export {
myFunc2,
unnecessary as omitme
}
```
If you don't import them in `js/index.js`, they won't work:
```javascript
import defaultImport, {myFunc2} from './mylib.js';
defaultImport();
myFunc2();
omitme();
```
## Run webpack with NPM
Create `webpack.config.js` to simplify the terminal command
```javascript
module.exports = {
entry: './js/index.js',
output: {
filename: 'dist/bundle.js'
}
};
```
Now we can run:
```
./node_modules/.bin/webpack
```
We can put this command in our `package.json` file:
```javascript
"scripts": {
"build": "webpack"
},
```
and run
```
npm run build
```
## Run webpack with Babel
First install the core transpiler, the loader which loads babel-plugins, and the es2015 plugin for babel:
```
npm install babel-core babel-loader babel-preset-es2015 --save-dev
```
Modify the webpack config to use these:
```javascript
module.exports = {
entry: './js/index.js',
output: {
filename: 'dist/bundle.js'
},
module: {
rules: [
{
test: /\.(js|jsx)$/, //for all files that end with js/jsx
use: {
loader: 'babel-loader', //use the babel loader to load:
options: {
presets: ["es2015"] //the es2015 compiler
}
}
}
]
}
};
```
Now use some ES2015 syntax in `js/index.js`:
```javascript
class Foo {
bar(){
console.log('classes!');
}
}
```
The result in `dist/build.js` is the ES5 version:
```javascript
var Foo = function () {
function Foo() {
_classCallCheck(this, Foo);
}
_createClass(Foo, [{
key: 'bar',
value: function bar() {
console.log('classes!');
}
}]);
return Foo;
}();
```
## Run webpack with JSX
Install react core, the dom manipulator, and the babel transpiler plugin:
```
npm install react react-dom babel-preset-react --save-dev
```
In `webpack.config.js` use the `babel-loader` to load the `react` plugin:
```javascript
use: {
loader: 'babel-loader',
options: {
presets: ["es2015", "react"]
}
}
```
Add a `main` tag and move our `script` tag to the bottom of `index.html`
```html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
</head>
<body>
<main></main>
<script src="dist/bundle.js" charset="utf-8"></script>
</body>
</html>
```
Write some react in `js/index.js`:
```javascript
import ReactDOM from 'react-dom'; //import react-dom from npm install dir
import React from 'react'; //import react from npm install dir
ReactDOM.render(
<h1 className="foo">Hello, world!</h1>,
document.querySelector('main')
);
```
## Run webpack dev server
Webpack dev server is an "all-in-one" package that
- provides a basic static file server that serves your front-end static html/css/js files
- watches your files and runs webpack when any of them change
- reloads your browser whenever webpack is run
Install it:
```
npm install webpack-dev-server --save-dev
```
Alter `package.json` to use webpack-dev-server instead of webpack
```javascript
"scripts": {
"build": "webpack-dev-server --open"
},
```
Now you can run
```
npm run build
```
and it will open up your browser automatically. Change a file, and see it reload.
**NOTE** Webpack doesn't actually write the transpiled files to disk. Instead it serves them from memory. You can delete the `dist` directory
```
rm -r dist
```
Loading…
Cancel
Save