23 | );
24 | }
25 | };
26 |
27 | export default Results;
28 |
--------------------------------------------------------------------------------
/notes/06 - Exercise.md:
--------------------------------------------------------------------------------
1 | ## Exercise: A few More Components
2 |
3 | We need to create a few more components and scaffold out our application.
4 |
5 | 1. A **Loader.js** component which will take a prop of "message" and display it. Your HTML should look like this:
6 |
7 | ```html
8 |
9 |
10 |
Your Message from props goes here
11 |
12 | ```
13 |
14 | 2. A **Beer.js** component, for now just render out `
Beer will go here
`
15 | 3. A **Results.js** component, for how just render out `
Results go here
`
16 | 4. A **Search.js** component, for now just render out `
Search goes here
`
17 | 4. A **Single.js** component, for now just render out `
26 | );
27 | }
28 | };
29 |
30 |
31 | export default Search;
32 |
--------------------------------------------------------------------------------
/gulpfile.js:
--------------------------------------------------------------------------------
1 | var gulp = require('gulp');
2 | var markdown = require('gulp-markdown');
3 | var zip = require('gulp-zip');
4 |
5 | var fs = require('fs');
6 | var notesTop = fs.readFileSync('notes/top.html');
7 | var notesBottom = fs.readFileSync('notes/bottom.html');
8 | var insert = require('gulp-insert');
9 |
10 | gulp.task('notes',function() {
11 | return gulp.src('notes/**/*.md')
12 | .pipe(markdown({
13 | gfm: true
14 | }))
15 | .pipe(insert.prepend(notesTop))
16 | .pipe(insert.append(notesBottom))
17 | .pipe(gulp.dest('notes-export'))
18 | .pipe(zip('gulp-notes.zip'))
19 | .pipe(gulp.dest('.'));
20 | });
21 |
22 | // gulp.task('exercises', function() {
23 | // gulp.src('./CODE/*')
24 | // .pipe(zip('gulp-exercises.zip'))
25 | // .pipe(gulp.dest('.'))
26 | // });
27 |
28 | gulp.task('default',['notes']);
29 |
--------------------------------------------------------------------------------
/notes/10 - Working in Beer-js.md:
--------------------------------------------------------------------------------
1 | ## Working in Beer.js
2 |
3 | So far we have passed all beers from `Main.js` → `Results.js` and passed each individual beer from `Results.js` → `Beer.js`.
4 |
5 | Working in `Beer.js`, how do we access the info about that beer? How did we pass it? **Props!** What was it called? **details**!
6 |
7 | So how do we access it inside `Beer.js`? `this.props.details`!
8 |
9 | First, let's import a few dependencies:
10 |
11 | ```js
12 | import slug from 'slugify';
13 | import { Link } from 'react-router-dom';
14 | ```
15 |
16 | Then work through the render function together:
17 |
18 | ```html
19 | render() {
20 | const { name, labels, id } = this.props.details;
21 | const image = labels ? labels.medium : 'notfound.jpg';
22 |
23 | return (
24 |
25 |
26 |
{name}
27 |
28 |
29 |
30 | );
31 | }
32 | ```
33 |
--------------------------------------------------------------------------------
/notes/12 - Exercise- Working with a Single-js.md:
--------------------------------------------------------------------------------
1 | ## Exercise: Working with a Single.js
2 |
3 | When you click on a beer you should see this:
4 |
5 | 
6 |
7 | We need to transform Single.js to display all the info about that beer. We are going to build Single.js as an exercise where you work with each other. Here are some notes:
8 |
9 | 1. Your Single.js will have 2 items in state: `beer` and `loading`
10 | 2. You will fetch the beer's info in a `loadBeer` method that you create for `Single.js` from `http://api.react.beer/v2/beer/${beerId}`.For example
11 | 3. You can access the URL variables (Like `beerId`) in `this.props.match.params`
12 | 4. Display the Loader with the words "Pouring a cold one!" while the Ajax request is working
13 | 5. Display at least the Beer name and the Beer description. We will work through the other bits together.
14 |
15 | The final output will look like this:
16 |
17 | 
18 |
--------------------------------------------------------------------------------
/notes/04 - Our Second React Component .md:
--------------------------------------------------------------------------------
1 | ## Our Second React Component
2 |
3 | Before we can display that component, we need a wrapper component that will hold all everything.
4 |
5 | At the end of the day, our JSX is going to look similar to this:
6 |
7 | ```html
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 | ```
20 |
21 | Create a component called `Main.js` in your components directory.
22 |
23 | In that file, we will need to do the same three things we do in every component:
24 |
25 | 1. Import React
26 | 2. Create the component with `React.createClass()`
27 | 3. Export your Component
28 |
29 | ```
30 | import React from 'react';
31 | import Header from './Header';
32 |
33 | class Main extends React.Component {
34 | render() {
35 | return (
36 |
37 |
38 |
39 | )
40 | }
41 | };
42 |
43 | export default Main;
44 | ```
45 |
46 | Now in `index.js` import Main: `import Main from './components/Main';` and switch out `` with ``.
47 |
48 | See where we are going with this? We indirectly display the `` because it's part of ``. Take a look at your React dev tools now.
49 | N
50 | 
51 |
--------------------------------------------------------------------------------
/finished/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
17 | React App
18 |
19 |
20 |
21 |
31 |
32 |
33 |
--------------------------------------------------------------------------------
/starter-files/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
17 | React App
18 |
19 |
20 |
21 |
31 |
32 |
33 |
--------------------------------------------------------------------------------
/notes/09 - Caching Beers in LocalStorage.md:
--------------------------------------------------------------------------------
1 | ## Caching Beers in LocalStorage
2 |
3 | You may notice that everytime we go back to the main page we need to re-load all the beers with our Ajax endpoint - and this is pretty slow.
4 |
5 | We can store the beer data in localStorage and when someone searches for "hops" or "ale", we will first check to see if we have the results in localStorage.
6 |
7 | In `Main.js`, above let's update our `loadBeers()` method
8 |
9 | ```diff
10 | loadBeers = (searchTerm = 'hops') => {
11 | + // Check for beers in local storage
12 | + const localStorageBeers = localStorage.getItem(`search-${searchTerm}`);
13 | + if (localStorageBeers) {
14 | + const localBeers = JSON.parse(localStorageBeers);
15 | + this.setState({ beers: localBeers, loading: false });
16 | + return; // stop before fetch happens!
17 | + }
18 |
19 | fetch(`http://api.react.beer/v2/search?q=${searchTerm}&type=beer`).then(data => data.json())
20 | .then((beers) => {
21 | console.log(beers);
22 | // filter for beers with images
23 | this.state.beers = beers.data.filter(beer => !!beer.labels);
24 | this.setState({beers : this.state.beers, loading:false });
25 | + // save to local storage in case we search for this again
26 | + localStorage.setItem(`search-${searchTerm}`, JSON.stringify(this.state.beers));
27 | })
28 | .catch(err => console.log(err))
29 | ```
30 |
--------------------------------------------------------------------------------
/readme.md:
--------------------------------------------------------------------------------
1 | # React Workshop
2 |
3 | Hey Everyone - Wes here. I'll be your instructor for the react workshop. I need you to do a few things before you come to the workshop.
4 |
5 | ## Getting Started
6 |
7 | 1. Make sure you have the latest version of Node.js installed. If you don't have it, or are an older version, you can visit Nodejs.org and download the installer.
8 | 2. Download the starter files + notes:
9 | * Download the zip here: https://github.com/wesbos/React-Beer-Me/archive/master.zip
10 | 3. Have a terminal application ready. The built in Mac OS terminal works just great though I find Windows users prefer to use CMDER -
11 | 4. `npm install` all dependencies before you come. cd into your `starter-files` directory and type `npm install`. If you aren't comfortable in the terminal, you may wait until the morning of the workshop to get a hand with this.
12 | 5. Make sure your text editor is setup to handle React. You may use any editor but here are some good ones:
13 | * [VS Code](https://code.visualstudio.com/) with the default JavaScript highlighter.
14 | * Sublime Text with [Babel-Sublime](https://github.com/babel/babel-sublime) syntax highlighter installed
15 | * [Atom](https://atom.io/) with the default JavaSCript
16 | 6. Install the React Dev Tools browser extension for either Chrome or Firefox - they are both available in their respective stores.
17 |
18 |
19 | If there are any questions, feel free to email me! wes@wesbos.com
20 |
21 |
--------------------------------------------------------------------------------
/notes/11 - Adding a Loading State.md:
--------------------------------------------------------------------------------
1 | ## Introducing a loading State
2 |
3 | A common task in applications is to show a loading indicator. We can use use a boolean stored on the state of ``.
4 |
5 | ```diff
6 | constructor() {
7 | this.state = {
8 | numBeers : 10,
9 | beers: [],
10 | + loading: true
11 | }
12 | }
13 | ```
14 |
15 | Then update our state inside the `loadBeers` method:
16 |
17 | ```diff
18 | loadBeers = (searchTerm = 'hops') => {
19 | + this.setState({ loading: true });
20 |
21 | // Check for beers in local storage
22 | const localStorageBeers = localStorage.getItem(`search-${searchTerm}`);
23 | if (localStorageBeers) {
24 | const localBeers = JSON.parse(localStorageBeers);
25 | this.setState({ beers: localBeers, loading: false });
26 | return; // stop before fetch happens!
27 | }
28 |
29 | fetch(`http://api.react.beer/v2/search?q=${searchTerm}&type=beer`).then(data => data.json())
30 | .then((beers) => {
31 | console.log(beers);
32 | // filter for beers with images
33 | const filteredBeers = beers.data.filter(beer => !!beer.labels);
34 | + this.setState({ beers: filteredBeers, loading: false });
35 | // save to local storage in case we search for this again
36 | localStorage.setItem(`search-${searchTerm}`, JSON.stringify(this.state.beers));
37 | })
38 | .catch(err => console.error(err));
39 | }
40 |
41 | ```
42 |
43 | Now in `Results.js` we can first check if the results are loading and display the `` accordingly:
44 |
45 | Require it:
46 |
47 | ```js
48 | import Loader from './Loader';
49 | ```
50 |
51 | and amend your render:
52 |
53 | ```diff
54 | render() {
55 | + if(this.props.loading) {
56 | + return
57 | + }
58 |
59 | return (
60 |
75 | );
76 | }
77 | }
78 |
79 | export default Single;
80 |
--------------------------------------------------------------------------------
/notes/14 - Deploying + Challenges.md:
--------------------------------------------------------------------------------
1 | # Deploying
2 |
3 | To generate a bundle ready for production, simply run `npm build`. This will generate an index.html file and a .js file that contains all your minified code.
4 |
5 | # Challenge Exercises
6 |
7 | ## Stateless Functional Components
8 |
9 | Sometimes we have components that _only include a render()_. There are no custom methods, no lifecycle hooks, though they may have propTypes.
10 |
11 | If this is the case, we use a simple function that simply returns some JSX.
12 |
13 | Let's take out Beer.js component:
14 |
15 | ```js
16 | class Beer extends React.Component {
17 | render() {
18 | const { name, labels, id } = this.props.details;
19 | const image = labels ? labels.medium : 'null.jpg';
20 |
21 | return (
22 |
23 |
24 |
{name}
25 |
26 |
27 |
28 | );
29 | }
30 | };
31 | ```
32 |
33 | We can convert that to a function that returns some JSX. Notice how we passed in props and replaced `this.props` with just `props`?
34 |
35 | ```js
36 | const Beer = function(props) {
37 |
38 | const { name, labels, id } = props.details;
39 | const image = labels ? labels.medium : 'null.jpg';
40 |
41 | return (
42 |
43 |
44 |
{name}
45 |
46 |
47 |
48 | );
49 | };
50 | ```
51 |
52 | You'll often also see it written with a one line arrow function with an implicit return.
53 |
54 | ```js
55 | const Hello = (props) => (
56 |
57 |
Hello {props.name}!
58 |
59 | )
60 | ```
61 |
62 | **Challenge:**
63 |
64 | ## Cache Single Beers
65 |
66 | Can you update the `Single.js` file to cache the single beer in localStorage? If I visit the same beer page twice, it should fetch it once.
67 |
68 | ## Modify It - Make it your own
69 |
70 | Now that you have a feel for React.js, what else could you build with it? This workshop should give you head start and the only way to continue learning is to build something that you are invested in.
71 |
72 | What can you build?
73 |
74 | * Use your own API to display it's data
75 | * Add a note taking feature to the beers
76 | * Build a shopping cart from scratch
77 | * re-do your WordPress website with the WP API
78 |
79 |
80 |
--------------------------------------------------------------------------------
/react-workshop.md:
--------------------------------------------------------------------------------
1 | # An Intro to React Workshop
2 |
3 | This is a 1 day, 6-8 hour workshop aimed at understanding the fundamentals of React. Throughout the day we will work to incrementally build an application touching all every major point of React:
4 |
5 | * Creating Components and writing HTML with JSX
6 | * Routing with React Router
7 | * Understanding State and holding data
8 | * Passing data between components with with Props
9 | * Fetching data from an Ajax endpoint
10 | * Persisting data with LocalStorage
11 | * Working with Events in React
12 | * Working with Forms, retrieving data from DOM inputs
13 | * Stateless Functional Components
14 | * React Deployment
15 |
16 | Together we will build , an interactive Beer explorer single page application. Along the way we will learn each fundamental concept, take time to implement it in our application and understand both the _Whys_ and _hows_ of the way React works.
17 |
18 | Students are expected to have Beginner to intermediate JavaScript skills — you should know how functions, variables, arguments and all the basics of JavaScript work.
19 |
20 | ## What To Bring
21 |
22 | Bring a laptop with:
23 |
24 | * the latest version of Node.js Installed - you can download the installer over at Nodejs.org. If you aren't sure if you have node installed, open a terminal window and type `node -v`, compare that against the latest version at http://nodejs.org
25 | * A terminal / command line application. For Windows I recommend [cmder](http://cmder.net/), though the built in one will work just fine. For OSX built in Terminal, [iTerm2](https://www.iterm2.com/) or [Hyper.app]https://hyperterm.now.sh/) will work as well.
26 | * A text editor. You may use any editor but here are some good ones:
27 | * Sublime Text with [Babel-Sublime](https://github.com/babel/babel-sublime) syntax highlighter installed
28 | * [Atom](https://atom.io/)
29 |
30 |
31 | ## About Wes Bos
32 | Wes Bos is a full stack developer and teacher from Hamilton, Canada. With a knack for breaking down technical concepts and converting them into fun, digestable bits, Wes creates some of the best online courses related to web development. He is the author or [React For Beginners](http://ReactforBeginners.com), [ES6 for Everyone](https://ES6.io), [What the Flexbox?!][http://flexbox.io] and [many other courses](http://wesbos.com/courses). You can catch Wes posting 🔥 Hot Tips on his [twitter](https://twitter.com/wesbos) where he is most active.
33 |
--------------------------------------------------------------------------------
/finished/src/components/Main.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import Results from "./Results";
3 | import Search from "./Search";
4 | import Header from "./Header";
5 |
6 | class Main extends React.Component {
7 | constructor() {
8 | super();
9 | this.state = {
10 | beers: [],
11 | loading: true
12 | };
13 | }
14 |
15 | componentDidMount() {
16 | console.log(`mounting`);
17 | console.log(this);
18 | const params = this.props.match.params || {};
19 | const searchTerm = params.searchTerm || undefined;
20 | this.loadBeers(searchTerm);
21 | }
22 |
23 | // componentWillReceiveProps(nextProps) {
24 | // console.log("Will receive props!");
25 | // console.log(nextProps);
26 | // this.loadBeers(nextProps.match.params.searchTerm);
27 | // }
28 | componentDidUpdate(prevProps) {
29 | console.log('did update');
30 | const currentSearchTerm = this.props.match.params.searchTerm;
31 | const oldSearchTerm = prevProps.match.params.searchTerm;
32 | if (currentSearchTerm !== oldSearchTerm) {
33 | this.loadBeers(currentSearchTerm);
34 | }
35 | }
36 |
37 | loadBeers = (searchTerm = "hops") => {
38 | this.setState({ loading: true });
39 |
40 | // Check for beers in local storage
41 | const localStorageBeers = localStorage.getItem(`search-${searchTerm}`);
42 |
43 | if (localStorageBeers) {
44 | const localBeers = JSON.parse(localStorageBeers);
45 | this.setState({ beers: localBeers, loading: false });
46 | return; // stop before fetch happens!
47 | }
48 |
49 | fetch(`http://api.react.beer/v2/search?q=${searchTerm}&type=beer`)
50 | .then(data => data.json())
51 | .then(data => {
52 | // filter for beers with images
53 | const beers = data.data || [];
54 | const filteredBeers = beers.filter(beer => !!beer.labels);
55 | this.setState({ beers: filteredBeers, loading: false });
56 | // save to local storage in case we search for this again
57 | localStorage.setItem(
58 | `search-${searchTerm}`,
59 | JSON.stringify(this.state.beers)
60 | );
61 | })
62 | .catch(err => console.error(err));
63 | };
64 |
65 | render() {
66 | return (
67 |
13 | ```
14 |
15 | But self-closing elements like `input` and `img` need to have the closing `/` in them:
16 |
17 | ```html
18 |
19 |
20 |
21 |
22 |
23 | ```
24 |
25 | ### Must return only one element
26 |
27 | React expects you to only return one element. You can have as many child elements as you wish, but only one top level element.
28 |
29 | So, if I needed to return the following HTML. You'll get an error saying `Adjacent JSX elements must be wrapped in an enclosing tag (8:6)`.
30 |
31 | ```html
32 |
Beer Name
33 |
Beer Description goes here
34 | ```
35 |
36 | An easy fix is to wrap it in a div:
37 |
38 | ```html
39 |
40 |
Beer Name
41 |
Beer Description goes here
42 |
43 | ```
44 |
45 | One major downside to this is that it interferes with CSS where the parent-child relationship is important. Extra divs can really goof up your Flexbox or CSS Grid code.
46 |
47 | As of React 16.2, we are now able to use something called Fragments which won't render out a containing div:
48 |
49 | ```js
50 | <>
51 |
Beer Name
52 |
Beer Description goes here
53 | >
54 | ```
55 |
56 | ### Comments
57 |
58 | Comments are a little weird in JSX, since we are _technically_ writing JavaScript, we need to use JavaScript comments, but inside JSX curly braces.
59 |
60 | So a comment in JSX looks like
61 |
62 | ```html
63 |
64 | {/* Comment here */ }
65 |
Beer Name
66 |
Beer Description goes here
67 |
68 | ```
69 |
70 | Another gotcha is that you may not have a comment at the top level, for the same reason we can only return one element:
71 |
72 | ```html
73 | {/* Comment cannot go here */ }
74 |
75 |
Beer Name
76 |
Beer Description goes here
77 |
78 | ```
79 |
80 | ### className instead of class
81 |
82 | Because `class` is a reserved word in JavaScript, you must use className instead.
83 |
84 | ```html
85 |
Hello
86 | ```
87 |
88 | is now
89 |
90 | ```html
91 |
Hello
92 | ```
93 |
94 | If you use Emmet, your expansions will be automatically updated for you.
95 |
--------------------------------------------------------------------------------
/notes/07 - React Router.md:
--------------------------------------------------------------------------------
1 |
2 | ## Routing with React Router
3 |
4 | Our application is going to have three "routes", or urls that a user can hit.
5 |
6 | 1. `localhost:3000/` for the home page and default beers
7 | 1. `localhost:3000/search/angry` the search results for a specific keyword. In this case `angry`
8 | 1. `http://localhost:3000/beer/OUqh1N/Texas-Craft-Brewers-Guild` the single view page for a specific beer - we pass along the beer ID and the beer name in the url.
9 |
10 | React is just a view library so it doesn't have routing built in like other frameworks might have. That said, the community has primarily standardized on using [React Router](https://github.com/ReactTraining/react-router)
11 |
12 | React router is just a component in itself - it watches for history changes and will render out the correct component for you.
13 |
14 | On every page we want to render either the `` component on the Home page and search page or the `` on the single beer page.
15 |
16 |
17 | ### Step 1: Import react-router
18 |
19 | There are a number of things we need from the `react-router-dom` package. In `index.js`, import the following:
20 |
21 | ```js
22 | import { BrowserRouter, Route } from 'react-router-dom';
23 | ```
24 |
25 | ### Step 2: Update our index.js Render
26 |
27 | In `index.js` we are going to change our out render function to take the router instead of the `` component.
28 |
29 | Currently it looks like this:
30 |
31 | ```html
32 | render(, document.querySelector('#root'));
33 | ```
34 |
35 | And we will update it to look like this. Let's code it together and talk though each of the parts.
36 |
37 | ```
38 | const Root = function() {
39 | return (
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 | );
48 | };
49 |
50 | render(, document.querySelector('#root'));
51 | ```
52 |
53 | **Finally,** you'll notice we are referencing the `Results` and `Single` components here. Make sure you import them at the top of your document alongside the already imported `Main`:
54 |
55 | Our entire `index.js` now looks like:
56 |
57 | ```html
58 | import React from 'react';
59 | import { render } from 'react-dom';
60 | import Main from './components/Main';
61 | import Single from './components/Single';
62 |
63 | import { BrowserRouter, Route } from 'react-router-dom';
64 |
65 | /* Import CSS */
66 | import './style.css';
67 |
68 | const Root = function() {
69 | return (
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 | );
78 | };
79 |
80 | render(, document.querySelector('#root'));
81 | ```
82 |
83 | ### Step 3: Try it out
84 |
85 | You should be able to go to any of the matching routes:
86 |
87 | *
88 | *
89 | *
90 |
--------------------------------------------------------------------------------
/notes/01 - Initial React Setup.md:
--------------------------------------------------------------------------------
1 | ## Env Setup
2 |
3 | In order to write React code, we need to have a little tooling in place.
4 |
5 | React is written in ES6 modules. Rather than use a bunch of Script tags and dump them into our code, we use ES6 modules to import and export our components. Much more on this as we go along.
6 |
7 | In order to work with modules, we need a few things:
8 |
9 | 1. **npm** — Used for installing our dependencies - like React!
10 | 2. **node.js** — the tooling we use runs on Node.js
11 | 3. **Webpack** — one of the most popular bundlers for JavaScript modules. We will be using Webpack behind the scenes with a command line tool called `create-react-app`.
12 | 4. **Terminal** — the bundling of our code happens in the Terminal so you'll need either the OSX terminal app or the Windows PowerShell installed
13 |
14 | So, let's head on over to our `beer-me` directory. The `package.json` file already includes the dependencies that we need, so we just need to run `npm install` to fetch and install them.
15 |
16 | Our webpack process is setup for using `index.js` as our entry point. Open it up and type:
17 |
18 | ```js
19 | alert('it works!');
20 | ```
21 |
22 | ## Running our App
23 |
24 | To start the app, simply run `npm start`. Webpack (via `create-react-app`) will build the site and open it up in your browser. Since all we have written so far is just a alert, you should see it when the browser opens.
25 |
26 | 
27 |
28 | ## Hello World in React
29 |
30 | Let's get a paragraph tag displayed on the page.
31 |
32 | First we need to import React and something called react-dom which will allow us to display HTML.
33 |
34 | Since both `react` and `react-dom` are both npm packages we we already installed, we can simply require the entire React lib, and then use curly brackets to import just the one `render` method from `react-dom`:
35 |
36 | ```js
37 | import React from 'react';
38 | import { render } from 'react-dom';
39 | ```
40 |
41 | Next, we need to render out something. React needs an entry point where it can "mount" itself. If you look at `index.html` you'll see that we have an empty div with the id of `root`.
42 |
43 | ```
44 | render(
Hello World
, document.querySelector('#root'));
45 | ```
46 |
47 | Let's break this down:
48 |
49 | 1. `render()` is the method we just imported
50 | 2.
Hello World
is the element we wish to render — this is really something called JSX. More on this in a bit! It's important to note thay we don't have to put it in quotes.
51 | 3. document.querySelector('#root') finds the entry point in the DOM
52 |
53 | Save and refresh your page, you should see the very basic of getting up and running with React. If you open your dev tools now you should see the React tab which you can now inspect:
54 |
55 | 
56 |
57 | ## CSS
58 |
59 | We have two options for using CSS with a React app.
60 |
61 | 1. You can load in a `style.css` file all on your own into your index.html and not have React or Webpack play any part of it.
62 | 2. You can let Webpack handle importing the CSS for you. The advantages of this is that you _could_ write CSS the directly relates to each component and only have it imported as you need it.
63 |
64 | This is a very divisive topic in the web development community so I'll let you make your own decisions here. For us, I'm going to import all our CSS at the top level app.
65 |
66 | In your `index.js`, place this just above your render:
67 |
68 | ```js
69 | /* Import CSS */
70 | import css from './style.css';
71 | ```
72 |
73 | I'm using plain cSS here - but you could use Sass, Less, Post CSS or regular CSS if you'd like.
74 |
75 | However, since this all happens inside the WebPack file with something called _loaders_, we would need to _eject_ from `create-react-app`. More on this later.
76 |
--------------------------------------------------------------------------------
/notes/02- Our First React Component.md:
--------------------------------------------------------------------------------
1 | ## Our First React Component
2 |
3 | Now - we can't just be writing all of our HTML inside of the render method — we need to break things up into their own components. Let's write our first React component.
4 |
5 | In React, everything is a component. You can think of our application as many parts that we piece together to make an application as a whole.
6 |
7 | Let's look at the front page of our app. What are the components we are going to make?
8 |
9 | 
10 |
11 | Let's start with a `Header.js` component. In react, since components are sort of like classes that can be reused over and over, it's a standard practice to name your files and components with a capital.
12 |
13 | So in a folder named `components`, create `components/Header.js`.
14 |
15 | Now there are a few things we need to create a component:
16 |
17 | 1. React itself
18 |
19 | ```js
20 | import React from 'react';
21 | ```
22 |
23 | Notice that even though we have imported React into `index.js`, we also import it in here. Modules are not global and you _must_ re-import the react library into every point that you need it.
24 |
25 | Then we create our component and store it in a variable. We extend `React.Component` to create the react class here.
26 |
27 | ## Quick Aside
28 |
29 | We are extending React.Component here with ES6 classes. Since ES6 classes currently fall short of a few much needed properties, we will be using some features that are "soon-to-come" to JavaScript to fill in those holes.
30 |
31 | The major shortcoming of ES6 classes and React is that the keyword `this` is not bound to the component instance. To get around this, we will be using [class properties](https://babeljs.io/docs/plugins/transform-class-properties/) which are not yet in the language but will be compiled down for us. I'll be sure to touch on this as we learn, but this is a heads up that you may see some JS syntax that you have never encountered before.
32 |
33 | ## Back to it
34 |
35 | Every React component will have multiple methods that live inside it, but the one method that we absolutely need is the `render()` method. This is a pre-defined method that React looks for when it displays the content on our page.
36 |
37 | Let's type this one together to get the hang of the syntax and answer the following questions along the way:
38 |
39 | 1. Why do we use `const`?
40 | 2. What is this `render() {}` business? should it not be `render: function() {}`?
41 | 3. Why is there (parens) around everything?
42 |
43 | ```js
44 | class Header extends React.Component {
45 | render() {
46 | return (
47 |
Beer Me!
48 | )
49 | }
50 | };
51 | ```
52 |
53 | Finally, since we will need to import this component into other components, we need to **export it** with `export default Header`.
54 |
55 | Our final code looks like this:
56 |
57 | ```js
58 | import React from 'react';
59 |
60 | class Header extends React.Component {
61 | render() {
62 | return (
63 |
Beer Me!
64 | )
65 | }
66 | };
67 |
68 | export default Header;
69 |
70 | ```
71 |
72 |
73 | ### Displaying ``
74 |
75 | We have now made a Header component. Swap out the `
Hello World
` with our new Header component in `index.js`. We can use the "tag" `` to reference our component:
76 |
77 | ```js
78 | render(, document.querySelector('#root'));
79 | ```
80 |
81 | But you'll see that we get this error:
82 |
83 | 
84 |
85 | That is because we haven't yet **imported** our component into index.js!
86 |
87 | ```js
88 | import Header from './components/Header';
89 | ```
90 |
91 | Since the component is not part of our `node_modules` directory, we do a relative reference with `./`. Refresh your page and you should now see the title:
92 |
93 |
94 | 
95 |
--------------------------------------------------------------------------------
/notes/05 - Passing Props.md:
--------------------------------------------------------------------------------
1 | ## Passing Props
2 |
3 | In React, there are two main ways in which you can provide data to a component — **state** and **props**. We're going to learn about props and later on, state.
4 |
5 | Our Header.js file is hard coded with "Beer Me!" — what if we had that data at the Main component and want to pass it down to Header?
6 |
7 | **To pass down data to a child component, we use props.**
8 |
9 | Props look just like attributes. Let's change our `` to take a prop called `siteName`.
10 |
11 | To pass the prop, simply pass it like an attribute:
12 |
13 | ```html
14 |
15 | ```
16 |
17 | You can pass any type down - strings, numbers, methods. Anything other than a string will need curly brackets:
18 |
19 | Pass down a property:
20 |
21 | ```html
22 |
23 | ```
24 |
25 | Use a function:
26 |
27 | ```html
28 |
29 | ```
30 |
31 | Pass a function
32 |
33 | ```html
34 |
35 | ```
36 |
37 | We will go more in depth on this soon!
38 |
39 | ### Using Props
40 |
41 | Once props are passed _to_ a component, we can use them access them inside that component. If you inspect your `` component with react dev tools you should now see that the there is an object inside the component called `props`:
42 |
43 | 
44 |
45 | We can access the props inside our render component by using `this.props.siteName`.
46 |
47 | ```html
48 |
55 | ```
56 |
57 | A few things to note:
58 |
59 | 1. Notice how we use `{curly braces}` to access variables inside our JSX?
60 | 2. React automatically binds all methods inside the component to the Component itself. What does that mean? In any method (render for this case) `this` refers to ``.
61 |
62 |
63 | ## PropTypes
64 |
65 | When using components, you don't always know which props you should be using. If a co-worker created the component, how do you know which props it requires?
66 |
67 | PropTypes will check that the necessary data, and the type of data being passed to the component is done correctly.
68 |
69 | So, anytime you use props, your component must have propTypes.
70 |
71 | Let's take `` in `Header.js` for example. What props do we use there?
72 |
73 | ```
74 | class Header extends React.Component {
75 | render() {
76 | return (
77 |
{this.props.siteName}
78 | );
79 | }
80 | };
81 | ```
82 |
83 | `siteName`!
84 |
85 | And what type is it? A String!
86 |
87 | First we need to import `PropTypes` from the `prop-types` package.
88 |
89 | ```
90 | import PropTypes from 'prop-types'
91 | // you can also import just the items you need:
92 | import { string, number } from 'prop-types';
93 | // you may also see an older style React.PropTypes. This is deprecated
94 | import { PropTypes } from 'react';
95 | ```
96 |
97 |
98 | So, we can add propTypes to our component:
99 |
100 | ```
101 | class Header extends React.Component {
102 |
103 | static propTypes = {
104 | siteName: PropTypes.string.isRequired
105 | }
106 |
107 | render() {
108 | return (
109 |
{this.props.siteName}
110 | );
111 | }
112 | };
113 | ```
114 |
115 | A few things:
116 | 1. We use `static propType =` to set the property on the component.
117 | 2. there is no `,` after the object or method. This is part of ES6 Classes and differs from an object where you must put a `,`
118 |
119 | This will now error in your console if you:
120 |
121 | 1) Forget to pass something
122 | 2) Pass a number, boolean, function or object.
123 |
124 | More info on all the available propTypes here:
125 |
126 |
127 |
--------------------------------------------------------------------------------
/notes/13 - Working with Forms + Search.md:
--------------------------------------------------------------------------------
1 | ## Working with Forms + Search
2 |
3 | The final piece of the puzzle is the search form. Let's start off by creating the markup for it in `Search.js`
4 |
5 | ```html
6 |
7 |
11 |
12 | ```
13 |
14 | The only thing that may seem out of place here so far is the `ref={(q) => this.q = q}` — we will reference this in just a second.
15 |
16 | When someone submits that form, we need to:
17 |
18 | 1. Stop the form from submitting
19 | 2. Get the value of the input
20 | 3. redirect them to `/search/whatever-they-searched-for`
21 |
22 | Let's take these three things and tackle them step by step:
23 |
24 | ### Stop the form from submitting
25 |
26 | How would you normally stop a form from submitting?
27 |
28 | You listen to for the `submit` event and call `preventDefault` on the event!
29 |
30 | So, we will modify our form tag: `