Warren Shea

Warren Shea’s Notes for React for Beginners - 2015v1 & 2018v2 (Online Course)

https://courses.wesbos.com/ | https://reactforbeginners.com/ | https://github.com/wesbos/React-For-Beginners-Starter-Files
Version: 20220729 | Status: Completed


Table of Contents


Module 01: Introduction, Tooling and Editor Setup

Module 02: Thinking and Understanding React Components

Module 03: Creating our First Components

class StorePicker extends React.Component {
  render() {
    return <p>Hello</p>
  }
}

render(<StorePicker/>,document.querySelector('#main'));
import React from 'react';
import { render } from 'react-dom';

import StorePicker from './components/StorePicker';

render(<StorePicker/>,document.querySelector('#main'));
import React from 'react';

class StorePicker extends React.Component {
  render() {
    return <p>Hello</p>
  }
}

export default StorePicker

Module 04: Writing HTML with JSX

return (
  All the HTML code you need
)
return (
  <form>
  </form>
)

This is not:

return (
  <form>
  </form>
  <p>
  </p>
)
return (
  <React.Fragment>
    <form>
    </form>
    <p>
    </p>
  </React.Fragment>
)

or

  return (
    <>
      <form>
      </form>
      <p>
      </p>
    </>
  )

Module 05: Loading CSS into our React Application

Module 06: Creating our application layout with components

import React from 'react';
import Header from './Header';
import Order from './Order';
import Inventory from './Inventory';

class App extends React.Component {
  render() {
    /* comment */
    return (
      <div className="catch-of-the-day">
        <div className="menu">
          <Header />
        </div>
        <Order />
        <Inventory />
      </div>
    );
  }
}

export default App;

Module 07: Passing Dynamic data with props

in `App.js`
<Header tagline="Fresh Seafood Market"/>

in `Header.js`
<h3 className="tagline-class">{this.props.tagline}</h3>

Module 08: Stateless Functional Components

class Header extends React.Component {
  render () {
    return (
      {/* code */}
    );
  }
}

You can use Stateless/Dumb/Pure/Simple Component:

const Header = props = > {
    return (
      {/* code....note, no this, so {props.tagline} */}
    );
}

const Header = props = > ( /* implicit return method */
    {/* code....note, no this, so {props.tagline} */}
)

const Header = ({tagline,age}) = > ( /* implicit return with destructuring */
    {/* code....note, no this, so {tagline} */}
)

Module 09: Routing with React Router

import React from 'react';
import { render } from 'react-dom';
import { BrowserRouter, Route, Switch } from 'react-router';

import StorePicker from './components/StorePicker';
import App from './components/App';
import NotFound from './components/NotFound';

const Router = () => {
  return (
    <BrowserRouter>
      <Switch>
        {/* For the root */}
        <Route exact pattern='/' component={StorePicker} />
        {/* For anything '/store' */}
        <Route path='/store/:storeId' component={App} />
        {/* For anything '/store' */}
        <Route component={NotFound} />
      </Switch>
    </BrowserRouter>
  )
}

render(<Router/>,document.querySelector('#main'));

Module 10: Helper and Utility Functions

Module 11: Working with React Events

import React from 'react';
import { getFunName} from "../helpers";

class StorePicker extends React.Component {
  handleClick() {
    console.log("clicked");
  }
  render() {
    return (
      <form>
        <button onclick={this.handleClick}>Click</button> {/* don't use this.handleClick() or it will run on mount */}
        <input
          type="text"
          placeholder="Store Name"
          defaultValue={getFunName()}
        />
        <button type="submit"></button
      </form>
    )
  }
}

export default StorePicker
<input
  type="text"
  placeholder="Store Name"
  defaultValue={getFunName()}
  ref={myInput} {/*this is deprecated, don't use that - FYI only*/
/>
<input
  type="text"
  placeholder="Store Name"
  defaultValue={getFunName()}
  ref={(myInput) => this.myInput = myInput} {/*this is deprecated, don't use that - FYI only*/
/>
import React from 'react';
import { getFunName} from "../helpers";

class StorePicker extends React.Component {
  constructor() {
    super();
    this.goToStore = this.goToStore.bind(this);
  }
  myInput = React.createRef();

  goToStore(event) {
    event.preventDefault(); /*stopped form from submitting*/
    console.log(this.myInput.value); /*grab text from box, this is the component only if goToStore is arrow function*/
  }
  render() {
    return (
      <form onSubmit={this.goToStore}>
        <input
          type="text"
          placeholder="Store Name"
          defaultValue={getFunName()}
          ref={this.myInput}
        />
        <button type="submit"></button
      </form>
    )
  }
}

export default StorePicker
import React from 'react';
import { getFunName} from "../helpers";

class StorePicker extends React.Component {
  myInput = React.createRef();

  goToStore = event => {
    event.preventDefault(); /*stopped form from submitting*/
    console.log(this.myInput.value.value); /*grab text from box, this is the component only if goToStore is arrow function*/
    /*this.myInput.value is React, this.myInput.value.value is JavaScript */
  }
  render() {
    return (
      <form onSubmit={this.goToStore}>
        <input
          type="text"
          placeholder="Store Name"
          defaultValue={getFunName()}
          ref={this.myInput}
        />
        <button type="submit"></button
      </form>
    )
  }
}

export default StorePicker

Module 12: Handling Event

...
  goToStore = event => {
    event.preventDefault(); /*stopped form from submitting*/
    const storeName = this.myInput.value.value; /*grab text from box, this is the component only if goToStore is arrow function*/
    /*this.myInput.value is React, this.myInput.value.value is JavaScript */
    this.props.history.push(`/store/${storeName}`); /*this.props is taking props from parent component, which is React Router */
  }
...

Module 13: Understanding State

class App extends React.Component {
  state = { //set initial state
    fishes: {},
    order: {}
  }

  addFish = fish => {
    const fishes = {...this.state.fishes}; /* 1. Take a copy of existing State, you don't want to reach into State and modify it directy */
    fishes[`fish${Date.now()}`] = fish; /* 2. Add new fishes to state */
    this.setState({ fishes }); /* 3. Update state with new fish */
  };
  render () {
    return (
      <div>
        <Inventory addFish={this.addFish} /> {/* addFish is passed down */}
      </div>
    );
  }
}
export default App;

Inventory.js

        <AddFishForm addFish={this.props.addFish} />

AddFishForm.js

class addFishForm extends React.Component {
  nameRef = React.createRef();
  priceRef = React.createRef();

  createFish = (event) => {
    event.preventDefault();
    const fish = {
      name: this.nameRef.value.value,
      price: parseFloat(this.nameRef.value.value), //float to store everything in cents
    };
    this.props.addFish(fish);
    event.currentTarget.reset(); //reset form
  }
  render () {
    return (
      <form className='fish-edit' onSubmit={this.createFish}>
        <input name="name" ref={this.nameRef} type="text" placeholder="Name" />
        <input name="price" ref={this.priceRef} type="text" placeholder="Price" />
        <button type='submit'>+ Add Fish</button>
      </form>
    );
  }
}
export default addFishForm;

Module 14: Loading data into state onClick

<button onClick={this.props.loadSampleFishes}>Load Sample Fishes</button>

We load in a fishes object from sample-fishes.js In App.js

import sampleFishes from '../sample-fishes'; //just an object with a lot of fishes

class App extends React.Component {
  state = { //set initial state
    fishes: {},
    order: {}
  }
  addFish = fish => {
    const fishes = {...this.state.fishes}; /* 1. Take a copy of existing State, you don't want to reach into State and modify it directy */
    fishes[`fish${Date.now()}`] = fish; /* 2. Add new fishes to state */
    this.setState({ fishes }); /* 3. Update state with new fish */
  };
  loadSamples = () => {
    this.setState({ fishes: sampleFishes });
  };
  render () {
    return (
      <div className='catch-of-the-day'>
        <Inventory addFish={this.addFish} loadSampleFishes={this.loadSampleFishes} /> {/* addFish is passed down */}
      </div>
    );
  }
}

Module 15: Displaying State with JSX

import sampleFishes from '../sample-fishes'; //just an object with a lot of fishes

class App extends React.Component {
  state = { //set initial state
    fishes: {},
    order: {}
  }
  addFish = fish => {
    const fishes = {...this.state.fishes}; /* 1. Take a copy of existing State, you don't want to reach into State and modify it directy */
    fishes[`fish${Date.now()}`] = fish; /* 2. Add new fishes to state */
    this.setState({ fishes }); /* 3. Update state with new fish */
  };
  loadSamples = () => {
    this.setState({ fishes: sampleFishes });
  };
  render () {
    return (
      <div className='catch-of-the-day'>
        <Header />
        <ul className="fishes">
          {
            Object
              .keys(this.state.fishes) //turn object into array
              .map(key => <Fish key={key} details={this.state.fishes[key]}/>)
          }
        </ul>
        <Order />
        <Inventory addFish={this.addFish} loadSampleFishes={this.loadSampleFishes} /> {/* addFish is passed down */}
      </div>
    );
  }
}

Fish.js as Simple/Pure/Dumb/Stateless Component

import React from 'react';

const Fish = ({ key, details }) => {
  const { image, name, price, desc, status } = details;
  return (
    <li className="menu-fish">
      <img src={image} alt={name} />
      <h3>{name}</h3>
      <span className="price">{formatPrice(price)}</span>
      <span className="description">{desc}</span>
    </li>
  );
}
export default Fish;

Module 16: Updating Order State

App.js

import sampleFishes from '../sample-fishes'; //just an object with a lot of fishes

class App extends React.Component {
  state = { //set initial state
    fishes: {},
    order: {}
  }
  // addFish function
  // loadSamples function
  addToOrder = key = {
    const order = {...this.state.order}; //copy order
    order[key] = order[key] + 1 || 1; //Add to order or, if it doesn't exist, add 1
    this.setState({ order }); //update State
  }
  render () {
    return (
      <div className='catch-of-the-day'>
        <Header />
        <ul className="fishes">
          {
            Object
              .keys(this.state.fishes) //turn object into array
              .map(key => <Fish key={key} index={index} details={this.state.fishes[key]} addToOrder={this.addToOrder}/>)
          }
        </ul>
        <Order />
        <Inventory addFish={this.addFish} loadSampleFishes={this.loadSampleFishes} /> {/* addFish is passed down */}
      </div>
    );
  }
}

import React from 'react';

const Fish = ({ details, addToOrder, index }) => {
  handleClick = () => {
    addToOrder(index);
  }
  const { image, name, price, desc, status } = details;
  const isAvailable = status === 'availabe';
  return (
    <li className="menu-fish">
      <img src={image} alt={name} />
      <h3>{name}</h3>
      <span className="price">{formatPrice(price)}</span>
      <span className="description">{desc}</span>
      <button disabled={!isAvailable} onClick={this.handeClick}>{ (isAvailable) ? "Add to Order" : "Sold Out!" }</button>
      {/* OR do it as a one liner */}
      <button disabled={!isAvailable} onClick={() => addToOrder(index)}>{ (isAvailable) ? "Add to Order" : "Sold Out!" }</button>
    </li>
  );
}
export default Fish;

Module 17: Displaying Order State with JSX

  <Order {...this.state}>

Reduce takes in data and takes in a tally

Module 18: Persisting our State with Firebase

componentDidMount () {
  const { params } = this.props.match
  this.ref = base.syncState(`${params.storeId}/fishes`, {
    context: this,
    state: 'fishes'
  });
}
componentWillUnmount () {
  base.removeBinding(this.ref);
}

Module 19: Persisting Order State with localstorage

componentDidMount () {
  const { params } = this.props.match;
  /* new */
  const localStorageRef = localStorage.getItem(params.storeId);
  if (localStorageRef) {
    this.setState({ order: JSON.parse(localStorageRef) });
  } /* new end */
  this.ref = base.syncState(`${params.storeId}/fishes`, {
    context: this,
    state: 'fishes'
  });
}

Module 20: Bi-directional Data Flow and Live State Editing

Module 21: Removing Items from State

Module 22: Animating React Components

import { TransitionGroup, CSSTransition } from "react-transition-group";

<TransitionGroup component="ul"> replacing <ul>
<CSSTransition classNames="order" key="{key}" timeout=> WRAPS <li>

Module 23: Component Validation with PropTypes

import PropTypes from "prop-types";

class Fish extends React.Component {
  static propTypes = {
    tagline: PropTypes.string.isRequired,
    functionA : PropTypes.func,
    details: PropTypes.shape({
      image: PropTypes.string,
      price: PropTypes.number
    })
  }
  ...
import PropTypes from "prop-types";

const Header = props => (
  ...
);

Header.propTypes = {
  tagline: PropTypes.string.isRequired,
  functionA : PropTypes.func,
  details: PropTypes.shape({
    image: PropTypes.string,
    price: PropTypes.number
  })
}

Module 24: Authentication

Module 25: Building React for Production

npm run build

Module 26: Deploying to Now

npm i -g now
now -v
npm i -g serve

Replace start with dev, create new start url

package.json

"start": "serve --single ./build"
now

will deploy to server

Use alias to deploy to same url

Module 27: Deploying to Netlify

Module 28: Deploying to an Apache Server

Module 29: Ejecting from create-react-app