notes and code from finished 'React For Beginners' course 📚
Switch branches/tags
Nothing to show
Clone or download
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Permalink
Type Name Latest commit message Commit time
Failed to load latest commit information.
catch-of-the-day
stepped-solutions
.gitignore
create-react-app-readme.md
notes.md
react-state-lesson_summary.txt
readme.md

readme.md

Course Notes, abridged

still a work in progress! 🤓

components

each component has:

  • key
  • props --> ex: likes, likers, etc
  • context
  • state

making a component

This is a basic component.

class StorePicker extends react.component {

}

each component needs a render method to put something to the DOM:

class StorePicker extends react.component {
 render() {
   return <p>hello</p>
 }
}

BUT HOW DOES THIS PUSH TO OUR DOM? ---> ReactDOM

import { render } from 'react-dom';

now we can use the render method to append to the DOM

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

  • you should put each of your components in a separate file.

make a component via components folder

import React from 'react';

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

export default StorePicker;

then import it in our index.js file: import StorePicker from './components/StorePicker';

^ NOTE: you have to import 'react' in every file you use it in!

JSX JSX = lets us write html in javascript much easier.

you could render html like this:

render() {
   return <p>hello</p>
}

but using JSX allows you to write cleaner html, using line breaks (that compilers dont trip up on). here's some JSX syntax:

render() {
   return (
      <form className="store-selector">

      </form>
   )
}

^ note className is used instead of class which is a taken namespace in React.

Also, this wont work:

render() {
   return (
      <form className="store-selector">

      </form>
      <p>yo</p>
   )
}

in react.render() there has to be ONE parent element.

  • with single tags, you must close them (ex: <input />)
  • JSX comment syntax: { /* words here */}
loading CSS into react app

In create-react-app, you can simply import the CSS in your index.js file: import './css/style.css';

Creating app layout with components

lets create a new component called 'App' in a file we'll create called App.js:

import React from 'react';

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

export default App;

then include it in main.js:

import App from './components/App';

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

^ nothing shows up because you must create (and import) your components. check the more extensive notes.md file for seeing how these components were created.

Passing Dynamic data with Props
  • so far all of our components have been static, but how do you get data from one component into another? PROPS.
  • html attributes help us supply additional info to a tag, and props do the same thing!

EX: in our app.js file: <Header tagline="Fresh Seafood Market"/>

and in header.js:

return (
   <header className = "top">
      <h1>Catch Of The Day</h1>
      <h3 className="tagline">{ this.props.tagline }</h3>
   </header>
)

this refers to the component (in our case, Header), and then grabs the props object and gets the specific value of the tagline key.

PROTIP: if you wanna debug something within the console....check out the $r property. basically, you can highlight the react component within the react developer tools tab, then use $r to troubleshoot the same way you would in the console normally.

EX: $r.props.tagline //Fresh Seafood Market

Stateless Functional Components

So far we've been making our components with class blah extends React.component {}.

Sometimes our components are super simple and just give html to the dom, we're not putting in other methods other than render in these cases. in that case we dont need to make a full React Component, we can use what we call a "stateless functional component."

But we've used React Components so far....how do we convert a react component to a 'stateless functional component'????

FROM THIS:

class Header extends React.Component {
   render() {
      return (
         <header className ="top">
            <h1>
               Catch
               <span className="ofThe">
                  <span className="of">Of</span>
                  <span className="the">The</span>
               </span>
               Day
            </h1>
            <h3 className="tagline"><span>{ this.props.tagline }</span></h3>
         </header>
      )
   }
}

TO THIS

const Header = (props) => {
 return (
      <header className ="top">
         <h1>
            Catch
            <span className="ofThe">
               <span className="of">Of</span>
               <span className="the">The</span>
            </span>
            Day
         </h1>
         <h3 className="tagline"><span>{ props.tagline }</span></h3>
      </header>
   )
}

^ so we take out the render() function and the class() declaration, put it into a variable called Header and create an anonymous function which uses props as a parameter. inside this function we put our return statement with our HTML.

^ also this.props is now changed to just props

Remember: stateless functional components just render out static HTML.

Routing with React Router

we'll use React Router, which is industry standard for using routing with react. This allows us to show/hide components depending on what page you're on.

we'll go to index.js and do some routing:

  1. import react router

import { BrowserRouter, Match, Miss } from 'react-router';

  1. Make a component that will be our router! Even our router is a component!

const Root = () => { return ( <Match exactly pattern="/" component={ StorePicker } /> ) }

^ this says,"hey when you're at the root level (/), show the StorePicker component."

const Root = () => {
   return (
   <BrowserRouter>
      <Match exactly pattern="/" component={ StorePicker } />
      <Match pattern="/store/:storeId" component={ App } />
   </BrowserRouter>
   )
}
  1. Now replace "App" with "Root" from: render(, document.querySelector('#main'));

to: render(, document.querySelector('#main'));

now this still doesnt work because FOR WHATEVER REASON cannot be a direct child of so we have to wrap it in a div:

const Root = () => {
   return (
   <BrowserRouter>
      <div>
         <Match exactly pattern="/" component={ StorePicker } />
         <Match pattern="/store/:storeId" component={ App } />
      </div>
   </BrowserRouter>
   )
}

we still have an error that states we aren't using the import that we've declared up top so lets include it in :

<Miss component={ NotFound } />

lets create a new file in /components called 'notFound.js':

import React from 'react';

class NotFound extends React.Component {
   render() {
      return (
         <p>not found</p>
      )
   }
}

export default NotFound;

now of course, you need to import it in index.js.

Working With React Events

  • events in react are the exact same as regular JS. only diff is that its wrapped in a cross-browser wrapper to make sure it works across all browsers.

  • Events are done INLINE in JS. <--no separation of concerns.

EX: in StorePicker.js:

class StorePicker extends React.Component {
   goToStore(event) {
      event.preventDefault();
      //grab text from the box
      //transition path
      console.log("you changed the URL");
   }
   render() {
      return (
         <form className="store-selector" onSubmit={ this.goToStore }>
            <h2>Please enter a store</h2>
            <input type="text" required placeholder="Store Name" defaultValue= { getFunName() } />
            <button type="submit">Visit Store</button>
         </form>
      )
   }
}

NOTE: as you see, there's no comma between the goToStore() method and the render() method...this is an ES6 class quirk, no commas.

to get the input value we actually dont want to mess with the DOM. in react you dont want to modify the DOM, you just want REACT to handle that part.

We do this with something called a REF, which is a reference to the actual input

EX:

   render() {
      return (
         <form className="store-selector" onSubmit={ this.goToStore }>
            <h2>Please enter a store</h2>
            <input type="text" required placeholder="Store Name" defaultValue= { getFunName() } ref={(input) => this.storeInput = input} />
            <button type="submit">Visit Store</button>
         </form>
      )
   }

^ we'll notice if we run the click event that when we try to console.log(this.storeinput), we get an error. upon trying to console.log(this) we see that 'this' is actually null. 'this' was initially a reference to the StorePicker class, and works fine for our render() method but not for other methods declared in the class. How can we reference the storepicker component inside of another method???

answer: when React switched to ES6 classes, it doesnt implicitly bind all the methods on our component to the method itself. if we want 'this' to equal 'StorePicker' theres a few things we need to do.

  1. use the constructor of a component. constructor = the bunch of code that runs when a component is created.
class StorePicker extends React.Component {
   constructor() {
      super();
   }

   goToStore(event) {
      event.preventDefault();
      console.log("you changed the URL");
      //grab text from the box
      console.log(this);
      //transition path
   }
   render() {
      return (
         <form className="store-selector" onSubmit={ this.goToStore }>
            <h2>Please enter a store</h2>
            <input type="text" required placeholder="Store Name" defaultValue= { getFunName() } ref={(input) => this.storeInput = input} />
            <button type="submit">Visit Store</button>
         </form>
      )
   }
}
  • super() is an es6 class feature which allows you to inherit stuff...in our case we inherit react.component class and then we also inherit the StorePicker class so now we can add to it.

now:

constructor() {
   super();
   this.goToStore = this.goToStore.bind(this);
}

^ it finds the goToStore() method in the class StorePicker, then sets its value to itself, but then binds it to 'this'. in the constructor, 'this' is equal to the StorePicker component.

  1. another way is you could run the same binding of this on submission of the form (within the render() method):

EX:

<form className="store-selector" onSubmit={ this.goToStore = this.goToStore.bind(this) }>
   <h2>Please enter a store</h2>
   <input type="text" required placeholder="Store Name" defaultValue= { getFunName() } ref={(input) => this.storeInput = input} />
   <button type="submit">Visit Store</button>
</form>
All About React Router 2 main ways you can change the page: 1. 2. The imperitive API:

Because is at the top level of our app (in index.js), we can access it basically anywhere in our app without having to do an ES6 import.

Context = declare something at the top level and its available to everyone on down. But dont pollute stuff globally!

lets surface our router in Storepicker.js...

Storepicker.contextTypes = {
   router: React.Proptypes.object
}

^ we declare this and it tells React, "hey, we need the router to be available to this StorePicker component" and it pulls it down for use.

if you refresh the page, then look for the StorePicker component in the React console tab, you'll see it now has a "Context" object with different methods on it. We're looking for the transitionTo() method.

Now inside our goToStore() method, we'll call this transitionTo() method:

goToStore(event) {
   event.preventDefault();
   //grab text from the box
   const storeId = this.storeInput.value;
   //transition path
   this.context.router.transitionTo(`/store/${storeId}`);
}

so once again, we click the button, this goToStore() event function is fired off, it grabs the value from the DOM using the ref attribute ( ref={(input) => this.storeInput = input} ), then uses the context object to access the router and transitionTo() method to push a user to another view. Phew!!

interesting: React uses the HTML5 push state, where a url is changed but it does not refresh your actual browser because everything is already loaded on the page.

Understanding State State: a representation of all the data in our application. Each component can have its own state, but you need to think about it as one object that holds all the data in our app or a piece of our app (component).

EX: state related to fishes component. state related to a customer's order.

  • In react, you store all your data in this master object called State and whenever you wanna change something on the page, you edit your state and let React handle your HTML for you.

  • In React you edit the data and react then edits the HTML.

  • whenever you change state, you don't have to wonder where state is being called and or for example...which views are where that header title lies. you can trust that wherever it is, its taken care of and updated.

simply update state and everything else that has been modeled with your JSX will be updated too.

To get a better understanding, lets...create a form for adding a fish.

in components directory, create 'AddFishForm.js':

import React from 'react';

class AddFishForm extends React.Component {
   render() {
      return (
         <form className="fish-edit">
            <input type="text" placeholder="Fish Name" />
            <input type="text" placeholder="Fish Price" />
            <select>
               <option value="available">Fresh!</option>
               <option value="unavailable">Sold Out!</option>
            </select>
            <textarea placeholder="Fish Desc"></textarea>
            <input type="text" placeholder="Fish Image" />
            <button type="submit">+ Add Item</button>
         </form>
      )
   }
}

export default AddFishForm;

now when someone submits a new Fish item, we want to create a fish object that takes the data and puts it into an object for us. lets create a method called createFish()...here we're going to be doing the same thing for binding that we did for StorePicker.js:

class AddFishForm extends React.Component {
   createFish(event) {
      event.preventDefault();
   }

<form className="fish-edit" onSubmit={ this.createFish = this.createFish.bind(this) }>

now when we type in these boxes, and submit using the button...how do we then take the text in the boxes and put it in an object?

using REFs!!!!!

 <form className="fish-edit" onSubmit={ this.createFish = this.createFish.bind(this) }>
            <input ref={(input) => this.name = input} type="text" placeholder="Fish Name" />
            <input ref={(input) => this.price = input} type="text" placeholder="Fish Price" />
            <select ref={(input) => this.status = input}>
               <option value="available">Fresh!</option>
               <option value="unavailable">Sold Out!</option>
            </select>
            <textarea ref={(input) => this.desc = input} placeholder="Fish Desc"></textarea>
            <input ref={(input) => this.image = input} type="text" placeholder="Fish Image" />
            <button type="submit">+ Add Item</button>
         </form>

and make sure to create your fish object above it:

class AddFishForm extends React.Component {
   createFish(event) {
      event.preventDefault();
      console.log("gonna make some fish!");
      <!--    const fish = {
      name:
      price:
      status:
      desc:
      image:
   } -->
   }

   render() {
      return (
         <form className="fish-edit" onSubmit={ this.createFish = this.createFish.bind(this) }>
            <input ref={(input) => this.name = input} type="text" placeholder="Fish Name" />
            <input ref={(input) => this.price = input} type="text" placeholder="Fish Price" />
            <select ref={(input) => this.status = input}>
               <option value="available">Fresh!</option>
               <option value="unavailable">Sold Out!</option>
            </select>
            <textarea ref={(input) => this.desc = input} placeholder="Fish Desc"></textarea>
            <input ref={(input) => this.image = input} type="text" placeholder="Fish Image" />
            <button type="submit">+ Add Item</button>
         </form>
      )
   }
}

now include the correct values:

class AddFishForm extends React.Component {
   createFish(event) {
      event.preventDefault();
      console.log("gonna make some fish!");

      const fish = {
         name: this.name.value,
         price: this.price.value,
         status: this.status.value,
         desc: this.desc.value,
         image: this.image.value
      }

      console.log(fish);
   }

   render() {
      return (
         <form className="fish-edit" onSubmit={ this.createFish = this.createFish.bind(this) }>
            <input ref={(input) => this.name = input} type="text" placeholder="Fish Name" />
            <input ref={(input) => this.price = input} type="text" placeholder="Fish Price" />
            <select ref={(input) => this.status = input}>
               <option value="available">Fresh!</option>
               <option value="unavailable">Sold Out!</option>
            </select>
            <textarea ref={(input) => this.desc = input} placeholder="Fish Desc"></textarea>
            <input ref={(input) => this.image = input} type="text" placeholder="Fish Image" />
            <button type="submit">+ Add Item</button>
         </form>
      )
   }
}

export default AddFishForm;

QUESTION: how do we use this fish object in our app or our STATE though?

State is always tied to a specific component. sometimes when a component needs to share state with other components...in our case Order, Inventory, and others...in this case we'll put out state on our parent component, , which wraps the others and can then be used on down.

  1. first, get initial state. React needs to know what to expect, so when the App component initializes, we need to tell it that we need a "fishes" state and an "orders" state.

we'll do this via a constructor method.

in App.js...

class App extends React.Component {
   constructor () {
   super();
   this.state = {
      fishes: {},
      order: {}
   }
   }
   render() {
      return (
        <div className="catch-of-the-day">
            <div className="menu">
               <Header tagline="Fresh Seafood Market"/>
            </div>
            <Order/>
            <Inventory/>
        </div>
      )
   }
}
  • call super() first so it inherits everything, we cant use "this" until we call super.
  • then this.state....state is ONE BIG OBJECT

now when we reload the page, go into react console and search for App, you see "state" object when clicked with our 2 created objects.

so we've got our state in app.js and we've got our fish object in AddFishForm.js...how does the fish object go to app.js?

first, we need to make a method on our App component called addFish();

class App extends React.Component {
   constructor () {
      super();
      //initial state
      this.state = {
         fishes: {},
         order: {}
      }
   }
   addFish(fish) {
   //update our state

   //set our state
   }
   render() {
      return (
        <div className="catch-of-the-day">
            <div className="menu">
               <Header tagline="Fresh Seafood Market"/>
            </div>
            <Order/>
            <Inventory/>
        </div>
      )
   }
}

when you want to update state, take a copy of your current state, then update your state. its kinda weird...you can do this:

   addFish(fish) {
   //update our state
   this.state.fishes.fish1 = fish;
   //set our state
   }

but its not best practice for performance. lets do it another way.

   addFish(fish) {
   //update our state
   const fishes = {...this.state.fishes};
   //set our state
   }

now lets add in our new fishes with individual keys. the easiest way to make unique keys is through timestamps to when their added...check it out:

   addFish(fish) {
   //update our state
   const fishes = {...this.state.fishes};

   //add in our new fish
   const timestamp = Date.now();
   fishes[`fish-${timestamp}`] = fish;

   //set our state
   }

now we need to set our state, by explicitly telling react which state we want to update. Rather than react watching our huge state object to update our DOM, we tell react "ok I updated this piece of state"....:

   addFish(fish) {
   //update our state
   const fishes = {...this.state.fishes};

   //add in our new fish
   const timestamp = Date.now();
   fishes[`fish-${timestamp}`] = fish;

   //set our state
   this.setState({ fishes: fishes});
   }

so we update our fishes object to being the updated fishes variable. now react is going to update the state anywhere that state is being used (across components).

However, if we look in our console, we cannot see the addFish() method upon searching for our component. thats because we have not binded the method to the constructor yet:

this.addFish = this.addFish.bind(this);

class App extends React.Component {
   constructor () {
      super();
      //initial state
      this.state = {
         fishes: {},
         order: {}
      }
      this.addFish = this.addFish.bind(this); //this right here
   }
   addFish(fish) {
   //update our state
   const fishes = {...this.state.fishes};

   //add in our new fish
   const timestamp = Date.now();
   fishes[`fish-${timestamp}`] = fish;

   //set our state
   this.setState({ fishes: fishes});
   }
   render() {
      return (
        <div className="catch-of-the-day">
            <div className="menu">
               <Header tagline="Fresh Seafood Market"/>
            </div>
            <Order/>
            <Inventory/>
        </div>
      )
   }
}

the last thing we need to do...how do we take the fish object created in AddFishForm.js and pass it to app.js?? how do we attach it?

this is where props comes in...

we've declared the addFish() method in our <app> component, now since we're using the addFish() method in various components, we attach the method via props where those components are declared inside the <app> component:

class App extends React.Component {
   constructor () {
      super();
      //initial state
      this.state = {
         fishes: {},
         order: {}
      }
      this.addFish = this.addFish.bind(this);
   }
   addFish(fish) {
   //update our state
   const fishes = {...this.state.fishes};

   //add in our new fish
   const timestamp = Date.now();
   fishes[`fish-${timestamp}`] = fish;

   //set our state
   this.setState({ fishes: fishes});
   }
   render() {
      return (
        <div className="catch-of-the-day">
            <div className="menu">
               <Header tagline="Fresh Seafood Market"/>
            </div>
            <Order/>
            <Inventory addFish= {this.addFish} />
        </div>
      )
   }
}

So this way we're passing the function down to a child component. Remember, Inventory component contains the AddFishForm component. so we declare it in the parent component, and its passed down to the child component Inventory, which then passes it down to its child component AddFishForm.

BUT now we have to go into Inventory.js and attach the addFish() method to where the AddFishForm component has been declared using PROPs.

REMEMBER: you pass data/functions down to child components via PROPS.

in Inventory.js

class Inventory extends React.Component {
   render() {
      return (
         <div>
            <h2>Inventory</h2>
            <AddFishForm addFish={this.props.addFish} />
         </div>
      )
   }
}

last thing: in our createFish() method inside the AddFishForm component, we need to declare this.props.addFish(fish); like this:

createFish(event) {
   event.preventDefault();
   const fish = {
      name: this.name.value,
      price: this.price.value,
      status: this.status.value,
      desc: this.desc.value,
      image: this.image.value
   }
   this.props.addFish(fish);
}

last thing is we want to reset the form. In AddFishForm.js:

  1. use a ref attribute to select the form
<form ref={(input) => this.fishForm = input }className="fish-edit" onSubmit={ this.createFish = this.createFish.bind(this) }>
  1. use a simple JS reset() method to clear it:
   createFish(event) {
      event.preventDefault();
      const fish = {
         name: this.name.value,
         price: this.price.value,
         status: this.status.value,
         desc: this.desc.value,
         image: this.image.value
      }
      this.props.addFish(fish);
      this.fishForm.reset();
   }

ADDITIONAL NOTES ON STATE ARE AVAILABLE IN SEPARATE FILE

Loading data into state onClick * In this lesson, we're going to put in some provided dummy data * when you click a button, grab the dummy data and pass it to a view.

EX: add an onClick function in the component

class Inventory extends React.Component {
   render() {
      return (
         <div>
            <h2>Inventory</h2>
            <AddFishForm addFish={this.props.addFish}/>
            <button onClick={this.loadSamples}>Load Sample Fishes</button>
         </div>
      )
   }
}

now instead of putting the loadSamples() method on our Inventory component, we'll put it where our state is declared. In our case, this is the <App> component:

in app.js (under the addFishes() method):

loadSamples() {
   this.setState = ({
      fishes:
   });
}

now we want to grab the sample fishes so lets import the sample-fishes file up top: import sampleFishes from '../SampleFishes';

now pass it to this.setState method:

loadSamples() {
   this.setState = ({
      fishes: sampleFishes
   });
}

now REMEMBER: in order to use this on a method successfully, you need to make sure to bind this to the component. so the same we did: this.addFish = this.addFish.bind(this);

we'll do the same for the loadSamples() method;

this.loadSamples = this.loadSamples.bind(this);

we then pass down this functionality to the child component that needs it via PROPS, in the same way that we added the addFish functionality via props as well:

<Inventory addFish={this.addFish} loadSamples={this.loadSamples}/>

and then change your onClick() function to reference the props:

From this: <button onClick={this.loadSamples}>Load Sample Fishes</button>

To this: <button onClick={this.props.loadSamples}>Load Sample Fishes</button>

So now we've got stuff hooked up like we did in the previous example, lets make sure to display the data now using JSX in the next tutorial...

Displaying State with JSX we'll make a component called `Fish.js` so we can reuse it:
import React from 'react';

class Fish extends React.Component {
   render() {
      return (
      <li className="menu-fish">😂</li>
      )
   }
}

export default Fish;

Now we'll import it in our app.js file:

render() {
   return (
     <div className="catch-of-the-day">
         <div className="menu">
            <Header tagline="Fresh Seafood Market"/>
            <ul className="list-of-fishes">
               <Fish/>
            </ul>
         </div>
         <Order/>
         <Inventory addFish={this.addFish} loadSamples={this.loadSamples}/>
     </div>
   )
}

we need to loop over every element in our state to grab all the fishes now...but of course looking at the return() statement, we're using JSX. JSX doesnt have any logic built-in, so no conditionals, no looping, etc. we literally can just use straight up JS within JSX.

when we use {} in JSX, that means we're using javascript. :) so lets use vanilla JS to loop over the fishes object:

   render() {
      return (
        <div className="catch-of-the-day">
            <div className="menu">
               <Header tagline="Fresh Seafood Market"/>
               <ul className="list-of-fishes">
                  {Object.keys(this.state.fishes)}
               </ul>
            </div>
            <Order/>
            <Inventory addFish={this.addFish} loadSamples={this.loadSamples}/>
        </div>
      )
   }

Object.keys() is a method that returns an array of the keys of an object. lets then use map() to iterate over each one and render out a <fish/> tag.

<ul className="list-of-fishes">
   {
   Object.keys(this.state.fishes)
   .map( key => <Fish/>)
   }
</ul>

Now this works but you get an error, because you now have like 9 components, and these components have the same name, so they need unique identifiers so you can modify them when you need to.

lets give them individual key PROPS:

<ul className="list-of-fishes">
   {
   Object.keys(this.state.fishes)
   .map( key => <Fish key={key} />)
   }
</ul>

Now we need to pass the individual fish details to our fish and we'll do this through a prop called "details":

<ul className="list-of-fishes">
   {
   Object.keys(this.state.fishes)
   .map( key => <Fish key={key} details={this.state.fishes[key] }/>)
   }
</ul>

Nice! So now we have the specific details for each fish stored in State thats being passed through a prop called "details".

Now we'll start creating our html for our <Fish/> component:

class Fish extends React.Component {
   render() {
      return (
         <li className="menu-fish">
            <img src={this.props.details.image} alt={this.props.details.name} />
         </li>
      )
   }
}

as you see, it inherits the details via props, but writing out 'this.props' the whole time is kinda annoying. lets massage the data here:

class Fish extends React.Component {
   render() {
       const details = this.props.details;
      return (
         <li className="menu-fish">
            <img src={details.image} alt={details.name} />
         </li>
      )
   }
}

Nice! lets finish it up

class Fish extends React.Component {
   render() {
       const details = this.props.details;
      return (
         <li className="menu-fish">
            <img src={details.image} alt={details.name} />
            <h3 className="fish-name">
               {details.name}
               <span className="price">{details.price}</span>
            </h3>
            <p>{details.desc}</p>
            <button>Add To Order</button>
         </li>
      )
   }
}

as you'll notice, the price is in cents. now lets convert it to dollars and cents using out helper function in helpers.js:

//import it
import { formatPrice } from '../helpers';

//use it
<span className="price">{formatPrice(details.price)}</span>

pretty cool.

Updating Order State We've created our "add to order" button, but when we click it, nothing happens. lets build it out.

First, <button>Add To Order</button>...the content here may change in this button depending on whether or not its available. put these variables in your component above the return function:

const isAvailable = details.status ==== 'available';
const buttonText = isAvailable ? 'Add to Order': 'Sold Out';

change this: <button>Add To Order</button> to this: <button>{buttonText}</button>

we also need to make the button disabled if sold out: <button disabled={!isAvailable}>{buttonText}</button>

Now we need to handle how to add to the order. lets create an addToOrder() function inside of app.js:

addToOrder(key) {
//first grab all of our existing state stuff
const order = {...this.state.order};

//update the state (either set it to 1 or increment it by 1)
order[key] = order[key] + 1 || 1;

//set the state
this.setState({order: order});
}

now back we need to go back to our App constructor function and bind this for this.addToOrder;

constructor () {
   super();
   //initial state
   this.state = {
      fishes: {},
      order: {}
   }
   this.addFish = this.addFish.bind(this); //dont understand this still.
   this.loadSamples = this.loadSamples.bind(this);
   this.addToOrder = this.addToOrder.bind(this);
}

Now of course, we add it to our component via PROPS:

<ul className="list-of-fishes">
   {
      Object
      .keys(this.state.fishes)
      .map( key => <Fish key={key} details={this.state.fishes[key]} addToOrder={this.addToOrder} />)
   }
</ul>

and use it within our component via this.props: <button disabled={!isAvailable} onClick={this.props.addToOrder}>{buttonText}</button>

Now if you'll check your <App> state, you'll see that your order object does in fact change, but you have one generic [object object] key/value pair for everything. we need to make sure each fish order has its own key/value pair:

<button disabled={!isAvailable} onClick={() => this.props.addToOrder('fish-1')}>{buttonText}</button>

Getting closer, but we want to get the unique key, not just fish-1. SO IT TURNS OUT, WE CANT ACCESS THE KEY INSIDE A COMPONENT. if you need to access it, you need to explicitly pass it down via a prop...we'll make one called 'index':

<ul className="list-of-fishes">
   {
      Object
      .keys(this.state.fishes)
      .map( key => <Fish key={key} index={key} details={this.state.fishes[key]} addToOrder={this.addToOrder} />)
   }
</ul>

now we can use it:

<button disabled={!isAvailable} onClick={() => this.props.addToOrder(this.props.index)}>{buttonText}</button>
</details>
<details>
<summary>Displaying Order State with JSX</summary>
so we've updated our state, now how do we display it?

In our `<Order/>` component, lets attach some props so we can use stuff in our `<App/>`'s state: `<Order fishes={this.state.fishes} order={this.state.order}/>`

now inside our `<Order>` component, lets add some stuff

class Order extends React.Component { render() { const orderIds = Object.keys(this.props.order); //this makes an array of the keys const total = orderIds.reduce((prevTotal, key) => { const fish = this.props.fish[key]; const count = this.props.order[key]; const isAvailable = fish && fish.status === 'available'; if(isAvailable) { return prevTotal + (count * fish.price || 0 ) } return prevTotal; }, 0); return (

Your Order

) } }


^ Here we create an array of keys called 'orderIds', then use `reduce()` to check if an item is available, and if so, return the total cost based on the price multiplied by the number of orders.

I've added a few new things to the Order component, which I'm not gonna explain for brevity's sake, but here's how we're looking now:

class Order extends React.Component { render() { const orderIds = Object.keys(this.props.order); //this makes an array of the keys const total = orderIds.reduce((prevTotal, key) => { const fish = this.props.fishes[key]; const count = this.props.order[key]; const isAvailable = fish && fish.status === 'available'; if(isAvailable) { return prevTotal + (count * fish.price || 0 ) } return prevTotal; }, 0); return (

Your Order

  • Total: {formatPrice(total)}
) } }


the plain js inside this render function is a lot, lets create a new function and put it above the `render()` function:

renderOrder(key) { const fish = this.props.fishes[key]; const count = this.props.order[key];

if (!fish || fish.status === 'unavailable') { return

  • Sorry, {fish ? fish.name : 'fish'} is no longer available!
  • } return (
  • {count}lbs {fish.name} formatPrice({count * fish.price})
  • ) }

    
    OK, looks nice but `this` is inside of a method, and doesnt point to state. we need to BIND `this` the same way we binded 'this' in the `<App>` component, inside a constructor:
    
    above `renderOrder()`:
    

    constructor(){ super(); this.renderOrder = this.renderOrder.bind(this); }

    here's your final result:

    import React from 'react';
    import { formatPrice } from '../helpers';
    
    class Order extends React.Component {
       constructor(){
          super();
          this.renderOrder = this.renderOrder.bind(this);
       }
       renderOrder(key) {
          const fish = this.props.fishes[key];
          const count = this.props.order[key];
    
          if (!fish || fish.status === 'unavailable') {
             return <li key={key}>Sorry, {fish ? fish.name : 'fish'} is no longer available!</li>
          }
          return (
             <li key={key}>
                <span>{count}lbs {fish.name}</span>
                <span className="price">{formatPrice(count * fish.price)}</span>
             </li>
          )
       }
       render() {
          const orderIds = Object.keys(this.props.order); //this makes an array of the keys
          const total = orderIds.reduce((prevTotal, key) => {
             const fish = this.props.fishes[key];
             const count = this.props.order[key];
             const isAvailable = fish && fish.status === 'available';
             if(isAvailable) {
                return prevTotal + (count * fish.price || 0 )
             }
             return prevTotal;
          }, 0);
    
          return (
          <div className="order-wrap">
             <h2>Your Order</h2>
             <ul className="order">
                {orderIds.map(this.renderOrder)}
                <li className="total">
                   <strong>Total:</strong>
                   {formatPrice(total)}
                </li>
             </ul>
          </div>
          )
       }
    }
    
    export default Order;
    
    Persisting our state with Firebase * firebase - google product, uses html5 websockets, meaning you can sync all your data from your app up to firebase and vice versa (when someone changes firebase, it changes our app). it allows us to have a backend db and make it real time, regardless of who has the app open, that data will always be synced to everyone's computer.
    • think of firebase as one big object...just like our state in react! if we can sync the two, we're golden
    1. set up firebase (we did this). we're going to setup our 'fishes' state to be synced to firebase. we'll use a package called "rebase" to do that.

    2. create a file at root called 'base.js', and import the rebase package. Inside base.js:

    import Rebase from 're-base';
    
    //this is a connection to our firebase DB
    const base = rebase.createClass({
       //we need to pass it: an API key, a domain we're connecting to, and DB URL
       //grabbed from Firebase site.
        apiKey: "AIzaSyCjztahJIp-1wRHdmZl2AD3KHLXW7_y1zg",
        authDomain: "catch-of-the-day-d-matheson.firebaseapp.com",
        databaseURL: "https://catch-of-the-day-d-matheson.firebaseio.com",
    })
    
    export default base;
    
    //now anytime we import 'base', now we can access this DB connection with any of our files. also if you wonder if its safe to have an API key client-side, thats where we're going to chat about authentication.
    
    1. now we'll import in app.js import base from '../base';

    now lets chat about the react "life cycle hooks"

    Life Cycle Hooks

    react has a component life cycle where we have entry points into a component, like when a component is being mounted or when it appears on the page where we can do an AJAX request, or check for a number of items, or in our case, connecting to rebase.

    we're going to be using one call "component will mount" which allows us to hook into the split second before our <App> component is rendered on the screen and allows us to sync our component state with our firebase state.

    theres other life cycle stuff: component will update, component did update, etc etc....there's a ton of hooks for these things in react.

    in App.js under our state, we'll create a componentWillMount() life cycle hook:

    componentWillMount() {
       this.ref = base.syncState(`${this.props.params.storeId}/fishes`, {
          context: this,
          state: 'fishes'
       });
    }
    

    this.ref says, hey, in firebase, sync the state of fishes within the specific store (${this.props.params.storeId}), and then we also need to pass in an object with the context and the state we want to sync...we could do orders, but we only want fishes.

    Also, what if we go to another store? we need to unmount it for performance reasons, we'll be racking up shit tons of listeners behind the scenes, so lets use the life cycle method componentWillUnmount():

    componentWillUnmount() {
       base.removeBinding(this.ref);
    }
    
    • this is insane because we can go into firebase, and straight up change our state from there. wild how its connected to our app...

    • now when we refresh the page, everything is persisted...we no longer have to load the sample fishes. now we dont have to worry like," ok, we changed our state, now let me change the DB"...this syncs perfectly and you only have to worry about STATE.

    • Persisting Order State with LocalStorage remember our hooks? componentWillMount(), componentWillUnmount(), etc? lets use ComponentWillUpdate(), which is run whenever PROPS or STATE changes:

    componentWillUpdate(nextProps, nextState) {
    
    }
    

    we'll use localStorage to store key/value pairs. so whenever the the state is updated, we'll store the new item, and whenever the page is refreshed or loading for the first time, we'll check localStorage for stuff and if theres stuff in there, will put it in the view.

    componentWillUpdate(nextProps, nextState) {
       localStorage.setItem(`order-${this.props.params.storeId}`);
    }
    

    heres the problem, our <App> component has params stored in its props, but the <Order> component does not. so how do we pass params from to its child component, <Order/> ? Through Props!!

    in App.js:

    <Order
       fishes={this.state.fishes}
       order={this.state.order}
       params={this.props.params}/>
    

    so thats taken care of, and our localStorage object has a valid key. Next, we need to set the value in localStorage:

    componentWillUpdate(nextProps, nextState) {
       localStorage.setItem(`order-${this.props.params.storeId}`, nextState.order);
    }
    

    nextState = the entire state.

    ^ This doesnt work because nextState.order is an object, so we need to use JSON.stringify() to parse it as a string:

    componentWillUpdate(nextProps, nextState) {
    localStorage.setItem(`order-${this.props.params.storeId}`, JSON.stringify(nextState.order));
    }
    

    And as we see here...localStorage is now updating with they key/value pairs of 'specific fish key': 'quantity of specific fish'...nice.

    WHAT!!! when we refresh our stuff is gone? maybe it needs localStorage.getItem()??

    it doesnt reinstate our order???

    you're correct in that we will use localStorage.getItem(), but we will use it in the componentWillMount() life cycle hook that will occur right before the component is rendered...we'll place it there:

    componentWillMount() {
       //this runs right before the App is rendered
       this.ref = base.syncState(`${this.props.params.storeId}/fishes`, {
          context: this,
          state: 'fishes'
       });
    
       //Check if there's any orders in localStorage
       const localStorageRef = localStorage.getItem(`order-${this.props.params.storeId}`);
    
       if (localStorage) {
          //update our App component's order state
          this.setState({
             order: localStorageRef
          });
       }
    }
    

    nice! however, we cant just set localStorageRef as the value, because its a string...we need to parse it using JSON.parse(): order: JSON.parse(localStorageRef)

    WORKING! so now we're able to persist out <Order> component state using localStorage

    Now thats the end of the lesson, but lets look a little bit more in depth to these 'life cycle methods' like 'componentWillMount()' and 'componentWillUnmount()':

    Course Detour: personal notes on life cycle hooks

    from the docs:

    • In apps with many components, its super important to free up resources taken by the components when theyre destroyed.

    • ex: we wanna set up a timer whenever is rendered to the DOM for the first time. This is called "mounting" in react. we also wanna clear the timer whenever the DOM produced by the component is removed...this is called "unmounting". we can declare special methods on the component class to run some code when a component mounts and unmounts:

    class Clock extends React.Component {
      constructor(props) {
        super(props);
        this.state = {date: new Date()};
      }
    
      componentDidMount() {
    
      }
    
      componentWillUnmount() {
    
      }
    
      render() {
        return (
          <div>
            <h1>Hello, world!</h1>
            <h2>It is {this.state.date.toLocaleTimeString()}.</h2>
          </div>
        );
      }
    }
    

    These methods are called 'LIFECYCLE HOOKS'.

    • componentDidMount() hook runs after the component output has been rendered to the DOM. This is a good place to set up a timer:
     componentDidMount() {
        this.timerID = setInterval(
          () => this.tick(),
          1000
        );
      }
    

    we'll remove this timer in the componentWillUnmount() lifecycle hook:

      componentWillUnmount() {
        clearInterval(this.timerID);
      }
    

    Finally we'll implement the tick() method that runs every second. It will use this.setState() to schedule updates to the component local state:

    class Clock extends React.Component {
      constructor(props) {
        super(props);
        this.state = {date: new Date()};
      }
    
      componentDidMount() {
        this.timerID = setInterval(
          () => this.tick(),
          1000
        );
      }
    
      componentWillUnmount() {
        clearInterval(this.timerID);
      }
    
      tick() {
        this.setState({
          date: new Date()
        });
      }
    
      render() {
        return (
          <div>
            <h1>Hello, world!</h1>
            <h2>It is {this.state.date.toLocaleTimeString()}.</h2>
          </div>
        );
      }
    }
    
    ReactDOM.render(
      <Clock />,
      document.getElementById('root')
    );
    

    I'm still a bit confused. What I think is happening is when the component is rendered to the DOM, the function tick() updates the state with the new date every second. when the state is updated, so is the view. we unmount this to free up our resources...is that right? when does it kill it? when the component is no longer rendered in the view?

    from the docs:

    Let's quickly recap what's going on and the order in which the methods are called:

    1. When <Clock /> is passed to ReactDOM.render(), React calls the constructor of the Clock component. Since Clock needs to display the current time, it initializes this.state with an object including the current time. We will later update this state.

    2. React then calls the Clock component's render() method. This is how React learns what should be displayed on the screen. React then updates the DOM to match the Clock's render output.

    3. When the Clock output is inserted in the DOM, React calls the componentDidMount() lifecycle hook. Inside it, the Clock component asks the browser to set up a timer to call tick() once a second.

    4. Every second the browser calls the tick() method. Inside it, the Clock component schedules a UI update by calling setState() with an object containing the current time. Thanks to the setState() call, React knows the state has changed, and calls render() method again to learn what should be on the screen. This time, this.state.date in the render() method will be different, and so the render output will include the updated time. React updates the DOM accordingly.

    5. If the Clock component is ever removed from the DOM, React calls the componentWillUnmount() lifecycle hook so the timer is stopped.

    Bi-directional Data Flow and Live State Editing In our `` component, we want it to be updated like the other two components. currently thats not the case, so lets change that. we'll create some js to render out the current inventory based on the state:

    in Inventory.js

    class Inventory extends React.Component {
       renderInventory(key) {
          return (
             <p>{key}</p>
          )
       }
    
       render() {
          return (
             <div>
                <h2>Inventory</h2>
                {Object.keys(this.props.fishes).map(this.renderInventory)}
                <AddFishForm addFish={this.props.addFish}/>
                <button onClick={this.props.loadSamples}>Load Sample Fishes</button>
             </div>
          )
       }
    }
    

    ALSO! we're getting an error because we have not attached our state to our component, so we cant access it via this.props...so lets do that in App.js: <Inventory addFish={this.addFish} loadSamples={this.loadSamples} fishes={this.state.fishes}/>

    Nice.

    Here's the final rendered html...NOTE: we use this.props.fishes[key] because renderInventory() is used inside of the map() function, so this is going to happen for each specific fish:

    class Inventory extends React.Component {
       renderInventory(key) {
          const fish = this.props.fishes[key];
          return (
          <div className="fish-edit" key={key}>
             <input type="text" name="name" value={fish.name} placeholder="Fish Name"/>
             <input type="text" name="price" value={fish.price} placeholder="Fish Price"/>
    
             <select type="text" name="status" value={fish.status} placeholder="Fish Status">
                <option value="available">Fresh!</option>
                <option value="unavailable">Sold Out!</option>
             </select>
    
             <textarea type="text" name="desc" value={fish.desc} placeholder="Fish Desc"></textarea>
             <input type="text" name="image" value={fish.image} placeholder="Fish Image"/>
          </div>
          )
       }
    
       render() {
          return (
             <div>
                <h2>Inventory</h2>
                {Object.keys(this.props.fishes).map(this.renderInventory)}
                <AddFishForm addFish={this.props.addFish}/>
                <button onClick={this.props.loadSamples}>Load Sample Fishes</button>
             </div>
          )
       }
    }
    ```
    but we forgot to bind `this`..lets create a constructor to do just that:
    ```
    class Inventory extends React.Component {
       constructor() {
          super();
          this.renderInventory = this.renderInventory.bind(this);
       }
    ```
    
    we're having a problem where we cant update the values in our `<inventory/>` component and we get a warning in the console. this is because react doesnt want you to stick state into an input unless you have a plan for updating it. react says,"if you put state in an input box, you must also give an instruction in terms of how to update that state" and thats important bc react doesnt want you to have state in your input box and in your regular state...it wants ONE core area and that's our application's state.
    
    SO we need to create a listener for the input to handle the state change:
    `<input type="text" name="name" value={fish.name} placeholder="Fish Name" onChange={(e) => this.handleChange(e, key)} />`
    
    Now lets create the method `handleChange()`:
    ```
    handleChange(e, key) {
       const fish = this.props.fishes[key];
    }
    ```
    and remember to bind `this` in `handleChange()`:
    
    `this.handleChange = this.handleChange.bind(this);`
    
    so now if we `console.log(fish)` inside the handler and test it, we'll see the individual fishes being console.logged on click. cool. now we need to do something verrrrry similar to what we've done before to update state.
    
    1. make a copy of existing state and add changed input values wherever they're changed. NOTE: e.target.name targets whatever element you've clicked on's name...when you update that value, it becomes `e.target.value`.
    ```
    const updatedFish = {
       ...fish,
       [e.target.name]: e.target.value
    };
    ```
    
    ```
    const updatedFish = {
       ...fish,
       [e.target.name]: e.target.value
    };
    ```
    
    now when we `console.log()` it we can see the changed state, but we're not updating our actual inventory, we need to take the updated fish and pass it to our `<App/>` which is then going to update it via state.
    
    lets make another method on our `<App/>` component called `updateFish()`:
    ```
    updateFish(key, updatedFish;) {
       const fishes = {...this.state.fishes};
    
       fishes[key] = updatedFish;
    
       this.setState({ fishes });
    }
    ```
    ^ verrrrry familiar, eh?
    
    Now lets add it into the `<Inventory/>` component via PROPS:
    ```
    <Inventory
       addFish={this.addFish}
       loadSamples={this.loadSamples}
       fishes={this.state.fishes}
       updateFish={this.updateFish}/>
    ```
    
    Now we'll make sure to bind `this` to our `updateFish()` method:
    `this.updateFish = this.updateFish.bind(this;`
    
    And now in our `handleChange()` method, we'll be sure to pass `updatedFish` to it:
    `this.props.updateFish(key, updatedFish);`
    
    Nice....so we're updating our state immediately. lets go through how this all works:
    
    `onchange` handler triggers when someone changes the name value, and that runs the `handleChange()` function, which takes a copy of the `fish`, overwrites the exsiting value into the new value, and then uses props to pass it up to our `updateFish()` function on our `<App/>` component to update our state by:
    
    1. taking a copy of existing fishes state
    2. adding the specific key's updated fish value
    3. setting the state to include the new state.
    
    seems like a lot, right? but when your app's get complicated, you'll love having your state in one place and not all your balls in the air.
    
    lets now add the event handlers for all the inputs:
    ```
    return (
    <div className="fish-edit" key={key}>
       <input type="text" name="name" value={fish.name} placeholder="Fish Name" onChange={(e) => this.handleChange(e, key)} />
       <input type="text" name="price" value={fish.price} placeholder="Fish Price" onChange={(e) => this.handleChange(e, key)}/>
    
       <select type="text" name="status" value={fish.status} placeholder="Fish Status" onChange={(e) => this.handleChange(e, key)}>
          <option value="available">Fresh!</option>
          <option value="unavailable">Sold Out!</option>
       </select>
    
       <textarea type="text" name="desc" value={fish.desc} placeholder="Fish Desc" onChange={(e) => this.handleChange(e, key)}></textarea>
       <input type="text" name="image" value={fish.image} placeholder="Fish Image" onChange={(e) => this.handleChange(e, key)}/>
    </div>
    )
    ```
    
    what's amazing: Firebase is still completely updating everything. how cool. this all occurs because theres only one state to take care of. one state to rule them all!
    </details>
    <details>
    <summary>Removing Items from State</summary>
    create removeFish()
    ```
    removeFish(key) {
     const fishes = {...this.state.fishes};
     delete fishes[key];
    }
    ```
    
    in our constructor, bind `this` to `removeFish()`:
    `this.removeFish = this.removeFish.bind(this);`
    
    but 'delete' does not work with Firebase!!!! so we need to instead set it to null:
    `fishes[key] = null;`
    
    and then set the state of `fishes`:
    ```
    removeFish(key) {
     const fishes = {...this.state.fishes};
     fishes[key] = null;
     this.setState({ fishes });
    }
    ```
    
    Nice! now lets pass this function to our `<Inventory/>` component via props:
    ```
    <Inventory
       addFish={this.addFish}
       loadSamples={this.loadSamples}
       fishes={this.state.fishes}
       updateFish={this.updateFish}
       removeFish={this.removeFish}/>
    ```
    
    now lets use it in our `<Inventory/>` component (in `inventory.js`):
    `<button onClick={(e) => this.props.removeFish(key)}>remove fish</button>`
    
    so it works!!! Now lets see if we can remove from the <Order/> component:
    
    ...OK I did it, but not repeating it in my notes.
    
    Interesting: put your JSX in a variable, then call the variable in your JSX like: {var name}
    
    ```
    const removeButton = <button onClick={() => this.props.removeFromOrder(key)}>&times;</button>
    
    <span>{removeButton}</span>
    ```
    </details>
    <details>
    <summary>Component validation with propTypes</summary>
    react kinda forces you to write structured code. sometimes react makes things harder than they should be, and thats because react is forcing us to write really well-structured and modular components.
    
    one thing to make modular components is PropTypes. you may want to share your components, and PropTyps allow us to validate the data that enter our components...
    EX:
    ```
    const Header = (props) => {
     return (
          <header className ="top">
             <h1>
                Catch
                <span className="ofThe">
                   <span className="of">Of</span>
                   <span className="the">The</span>
                </span>
                Day
             </h1>
             <h3 className="tagline"><span>{ props.tagline }</span></h3>
          </header>
       )
    }
    ```
    
    `props.tagline` needs to be a string...we built this thing so we know that it is a string, but PropTypes guarantees that it needs to be a string...its a nice safety guard.
    
    we'll go through all of our components and add propTypes to them:
    ```
    import React from 'react';
    
    const Header = (props) => {
     return (
          <header className ="top">
             <h1>
                Catch
                <span className="ofThe">
                   <span className="of">Of</span>
                   <span className="the">The</span>
                </span>
                Day
             </h1>
             <h3 className="tagline"><span>{ props.tagline }</span></h3>
          </header>
       )
    }
    
    Header.propTypes = {
       tagline: React.PropTypes.string
    }
    
    export default Header;
    ```
    
    now if you pass in say, a number, where the component is declared, you will get an error in your console:
    
    From:
    ` <Header tagline="Fresh Seafood Market"/>`
    
    To:
    `<Header tagline= {50}/>`
    
    now we can also state that the 'tagline' prop is required:
    ```
    Header.propTypes = {
       tagline: React.PropTypes.string.isRequired
    }
    ```
    
    good rule of thumb: anytime you pass a prop in a component, declare the propType.
    
    lets go through our existing components and add proptypes....
    ```
    AddFishForm.propTypes = {
       addFish: React.PropTypes.func.isRequired
    }
    ```
    
    OR...
    ```
    Order.propTypes = {
       removeFromOrder: React.PropTypes.func.isRequired,
       order: React.PropTypes.object.isRequired,
       fishes: React.PropTypes.object.isRequired
    }
    ```
    </details>
    <details>
    <summary>Authentication</summary>
    we need to create a login in our app.
    how do you do authentication when youre only client side? using firebase.
    
    we'll do 2 things:
    1. lock down the client-side where ppl cant see the form to edit it
    2. go into firebase, and reject people if they sneak past the client-side controls
    
    in firebase, go to 'authentication' tab...
    click 'set up sign-up method'
    
    1. we'll turn on Facebook, but first we need to register on developers.facebook.com/
    2. grab the Oauth redirect URI given in firebase:
       https://catch-of-the-day-d-matheson.firebaseapp.com/__/auth/handler
    3. paste it in FB login screen, and "check" the tab for "embedded browser OAuth login"
    4. click 'save changes'
    5. go to the 'dashboard' and copy the "app ID"
    6. paste it into the firebase authentication section for 'app ID'
    7. similarly, copy the 'secret' in the FB dashboard and paste it in the 'secret' section of firebase.
    8. click save
    
    we wanna do the same for twitter and github, but I just rather do fb to get the basic understanding down.
    
    NOTE: see how we're putting this in firebase, NOT client-side.
    
    Now lets open our `<Inventory/>` component and create a method to render out the buttons:
    ```
       renderLogin() {
          return (
             <nav className="login">
                <h2>Inventory</h2>
                <p>Sign in to manage your store's inventory</p>
                <button className="facebook" onClick={() => this.authenticate('facebook')}>Log In With Facebook</button>
             </nav>
          )
       }
    ```
    
    Also, make sure to bind `this` for `renderLogin()` in the constructor!
    `this.renderLogin = this.renderLogin.bind(this);`
    
    we'll create the `authenticate()` method soon, but we want to go into our `render()`
    function first...
    
    ```
    //check they are not logged in at all
    if(!this.state.uid) {
       render <div>{this.renderLogin()}</div>
    }
    ```
    
    now if we run our program and check it, we have errors because 'uid' has not been declared. lets declare that inside our constructor:
    ```
    this.state = {
       uid: null,
       owner: null
    }
    ```
    now our console is fine...
    
    nice! it runs.
    
    but we need to check if the user is the owner of the current store (the specific URL..in my current case its 'http://localhost:3000/store/ugliest-repulsive-halves')
    ```
    //check if they are the owner of the current store
    if(this.state.uid !== this.state.owner) {
       return (
          <div>
             <p>Sorry, you aren't the owner of this store!</p>
          </div>
       )
    }
    ```
    
    keep in mind these two functions will be fired after the `authenticate()` method...
    we also need a 'logout' button: `const logout = <button>Log Out!</button>;`
    
    and put it in our previous function:
    ```
    //check if they are the owner of the current store
    if(this.state.uid !== this.state.owner) {
       return (
          <div>
             <p>Sorry, you aren't the owner of this store!</p>
             {logout}
          </div>
       )
    }
    ```
    
    now we also put our 'logout' button in our actual rendered code so users have the chance to log out once theye logged in:
    `{logout}`
    
    now lets create the `authenticate()` method:
    ```
    authenticate(provider) {
       console.log(`trying to log in with ${provider}`);
    }
    ```
    
    make sure to bind `this` for `this.authenticate`
    
    nice...it works when we click the button...but what is 'provider'?
    
    now since we've got everything working, lets hook up firebase.
    
    Remember when we create `base.js`? this file contains our URL keys and database URL, and all that good stuff so we can work seamlessly.
    
    First lets import the 'base' file in order to use firebase: `import base from '../base'`.
    
    and now in our `authenticate()` method:
    ```
    authenticate(provider) {
       console.log(`trying to log in with ${provider}`);
       base.AuthWithOAuthPopup(provider);
    }
    ```
    
    now when the person successfully authenticates, we need a callback function, an `authHandler()` function.
    ```
    authenticate(provider) {
       console.log(`trying to log in with ${provider}`);
       base.authWithOAuthPopup(provider, this.authHandler);
    }
    ```
    
    lets create that:
    ```
    authHandler(err, authData) {
       console.log(authData);
    }
    ```
    
    Oh DONT FORGET to bind `this` for the `authenticate()` method.
    
    NIIIIIIIIICE!
    
    so what this does is actually pop up the facebook authentication method..and when we click "ok" it sends back the 'authData' that is console.logged...its an object with 'credential' and 'user' key/value pairs.
    
    we now need to store this authData data in state so that we can re-render the `inventory` component like a single sign-on:
    ```
    authHandler(err, authData) {
       console.log(authData);
       if (err) {
          console.log(err);
          return;
       }
    
       //grab the store info
    }
    ```
    
    heres what we'll do:
    
    we'll connect to firebase, grab a copy of all the info about the current store, then we'll see if the user owns the current store or not, if not is someone else the owner? if thats not true, we'll set the current user as the owner...
    
    `base.database()` <--this connects us directly to our firebase db to connect with any of their apis:
    ```
    authHandler(err, authData) {
       console.log(authData);
       if (err) {
          console.log(err);
          return;
       }
    
       //grab the store info
       const storeRef = base.database().ref(this.props.storeId);
    }
    ```
    
    now we gotta back up here; before declaring `this.props.storeId`, we have to include it within our `<Inventory/>` component in `app.js`:
    ```
    <Inventory
       addFish={this.addFish}
       loadSamples={this.loadSamples}
       fishes={this.state.fishes}
       updateFish={this.updateFish}
       storeId={this.props.params.storeId}
       removeFish={this.removeFish}/>
    ```
    
    then we also need to declare the PropType inside our `<Inventory/>` component:
    ```
    Inventory.propTypes = {
       removeFish: React.PropTypes.func.isRequired,
       fishes: React.PropTypes.object.isRequired,
       loadSamples: React.PropTypes.func.isRequired,
       addFish: React.PropTypes.func.isRequired,
       updateFish: React.PropTypes.func.isRequired,
       storeId: React.PropTypes.string.isRequired
    }
    ```
    
    now lets go back to our `authHandler()` method:
    ```
      authHandler(err, authData) {
          console.log(authData);
          if (err) {
             console.log(err);
             return;
          }
    
          //grab the store info
          const storeRef = base.database().ref(this.props.storeId);
    
          //query the firebase once for the store data
          storeRef.once( 'value', (snapshot) => {
             const data = snapshot.val() || {};
          });
       }
    ```
    
    `snapshot` refers to which is firebase's object of all the data...you have to call `cal()` on it to get the value.
    
    next we'll claim the store as our own if there is no current owner.
    ```
    //claim the store as our own if there is no owner already
    if(!data.owner) {
       storeRef.set({
          owner: authData.user.uid
       });
    }
    ```
    
    nice...so if we log in, we can then go into firebase and select 'database', and then select our specific URL, we can now see our uid value setting us up as the owner of that DB.
    
    that works but we still cant see our `<Inventory/>` stuff! no fishes to load nothing....so we need to set the state locally in our app as well:
    ```
    this.setState({
       uid: authData.user.uid,
       owner: data.owner || authData.user.uid
    })
    ```
    
    Nice! so now through setting the state, we've gotten to a point where we can render our view.
    
    Now what we want to do is make sure the data persists when we refresh the page, and we will use the native lifeCycle method `componentDidMount()`, and we'll place it up after the `constructor()` function:
    ```
    componentDidMount() {
       base.onAuth((user) => {
          if(user) {
             this.authHandler(null, { user });
          }
       });
    }
    ```
    base = database, `onAuth` is like `onClick` but checks if auth has happened. so remember 'user' is within the `authData` object that is passed back on success. we've also already created the `authHandler()` method, which grabs the specific store's specific info, checks if theres no current owner, and assigns the owner. we run this function `authHandler()` whenever a person signs in, but using `componentDidMount()` we'll run it every time the browser is refreshed. this will persist our data.
    
    and it works!
    
    now we need to log out
    ```
    logout() {
       base.unauth(); //logs us out of firebase
       this.setState({
          uid: null
       });
    }
    ```
    
    of course lets bind `this` for `logout()`: `this.logout = this.logout.bind(this);`
    
    and go to our logout button of course, and set the method on click:
    `const logout = <button onClick={this.logout}>Log Out!</button>;`
    
    and it signs you out...pretty amazing. cant believe I created an authentication system with react. wow.
    
    
    
    Last thing:
    we've nailed down the client-side, but we need to make sure no one with some firebase know-how can get around our authentication stuff too.
    
    lets go into firebase, select database > rules...its currently 'true' for reading and writing.
    
    Paste in these security rules:
    ```
    // These are your firebase security rules - put them in the "Security & Rules" tab of your database
    {
        "rules": {
            // won't let people delete an existing room
            ".write": "!data.exists()",
            ".read": true,
    
            "$room" : {
              // only the store owner can edit the data
              ".write" : "newData.child('owner').val() === auth.uid",
              ".read" : true
            }
        }
    }
    ```
    
    * anyone can read
    * you can write as long as no data exists
    * in each individual 'room', only the store owner gets to actually edit data to that individual store.
    </details>