commit
1fce93a165
@ -0,0 +1,134 @@
|
|||||||
|

|
||||||
|
|
||||||
|
# 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 @@
|
|||||||
|

|
||||||
|
|
||||||
|
# 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 @@
|
|||||||
|

|
||||||
|
|
||||||
|
# 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 @@
|
|||||||
|

|
||||||
|
|
||||||
|
# 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
|
||||||
|
});
|
||||||
|
}
|
||||||
|
```
|
||||||
@ -0,0 +1,723 @@
|
|||||||
|

|
||||||
|
|
||||||
|
# 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]
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
- See more information about when the method was defined implemented:
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
## 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:
|
||||||
|
|
||||||
|

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

|
||||||
|
|
||||||
|
## 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 @@
|
|||||||
|

|
||||||
|
|
||||||
|
# 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 @@
|
|||||||
|

|
||||||
|
|
||||||
|
# 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 @@
|
|||||||
|

|
||||||
|
|
||||||
|
# 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 @@
|
|||||||
|

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

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

|
||||||
|
|
||||||
|
# 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…
Reference in new issue