dcbeergoddess / react-traversy-2021

Follow Along with Traversy Media React Crash Course 2021 https://www.youtube.com/watch?v=w7ejDZ8SWv8

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

React JS Crash Course 2021

Follow Along with Traversy Media React Crash Course 2021 GITHUB REPO FROM BRAD

What is React?

  • React is a library for building user interfaces
  • React runs on the client as a SPA(Single Page App), but can be used to build full stack apps by communicating with a server/API (eg. MERN stack)
  • React is often refereed to as a front-ent "framework" because it is capable and directly comparable to a framework such as Angular or Vue

Why Would You Use React

  • MVC (Model View Controller) --> Structure the "view" layer of your application
  • Reusable components with their own state
  • JSX - Dynamic markup --> write dynamic HTML (JS formatted like HTML)
  • Interactive UIs with Virtual DOM --> Document Object Model --> Update parts of page without reloading it
  • Performance & Testing --> All Data immutable (can't mutate directly), easier to work on teams
  • Very Popular in the Industry

UI Components

  • When using React, think of your UI as a bunch of separate components

Components: Functions vs. Classes

Functions vs. Classes

  • Focus on Functions with Hooks
  • JSX (JavaScript Syntax Extension) - syntactic sugar
  • Can pass in "props" --> essentially attributes

Working with State

  • Components can have "state" which is an object that determines how a component renders and behaves (ex: collapsible menu, list of tasks, any data you bring into your compnents)
  • "App" or "global" state refers to state that is available to the entire UI, not just a single component (share data with multiple components when global state gets complicated --> Redux (3rd Party Manager) or Context API)
  • Prior to React 16.8, we had to use class based components to use state. Now we can use functional component with HOOKS (functional components used to be dumb components)

React Hooks

React Hooks are functions that le us hook into the React state and lifecyle features from function components

  • useState --> Returns a stateful value and a function to update it
  • useEffect --> Perform side effects in function components --> when making HTTP requests
  • useContext, useReducer, useRef --> Beyond the scope of this course
  • You can also create your own Custom Hooks

Create a New React App

  npx create-react-app my-app
  cd my-app
  npm start
  • MY GITHUB REPO OF REACT TASK TRACKER APP
  • Here's a look at what you get, in the package.json you have some dependencies --> if in react native you would see react-native instead of react-dom new react app
  • Look of the index.js and index.html --> App is the Route Component (every component we create will end up in main App component) index.js and index.html
  • Use index.html to add Bootstrap CDN, etc.
  • In App.js --> we see function component with JSX(looks like HTML) React App.js
  • instead of for attribute use htmlFor
  • instead of class attribute use className
  • dynamic --> can have JS expressions and variables src={logo}
  • Clean up some files and delete what is in the div
  • CAN ONLY HAVE ONE PARENT ELEMENT, CAN NOT ADD NEW H2 AFTER THE DIV Clean up App.js
  • if you didn't want a div inside a div you can use fragments <> to surround the two headers. html in dev console
  • You can create variables, ternary operators, ect. and use with JSX JSX EXAMPLES

CREATE COMPONENTS

  • GREAT VS CODE EXTENSION
Name: ES7 React/Redux/GraphQL/React-Native snippets
Id: dsznajder.es7-react-js-snippets
Description: Simple extensions for React, Redux and Graphql in JS/TS with ES7 syntax
Version: 3.1.1
Publisher: dsznajder
VS Marketplace Link: https://marketplace.visualstudio.com/items?itemName=dsznajder.es7-react-js-snippets
  • rcc - class based component
  • rce - class component and export at bottom
  • rafce - arrow function that exports at bottom
  • Creates boilerplate of a function component --> DO NOT NEED IMPORT REACT ANYMORE (unless you are creating a class)
  • use _rafce to skip import addition function boilerplate
//EXAMPLE OF USING A CLASS
import React, { Component } from 'react'

export class Header extends Component {
  render() {
    return (
      <div>
        
      </div>
    )
  }
}

export default Header
  • import component into App.js import component
//EXAMPLE OF IMPORTING A CLASS
import React from 'react'
import Header from './components/Header'

class App extends React.Component {
  render() {
    return <h1>Hello from a class</h1>
  }
} 

Pass in Component Props

  • How to pass in props and use them pass in title props
  • can set default props if none is passed in default props
  • can destructure props destructure props
  • There are also Prop Types --> make code more robust --> use impt with extension --> you can also use Typescript with React
  • Use and pass in number instead of string for title, will render with warnings in the console setting prop types
  • Set PropType to be required require prop types

Styling

  1. Can use stylesheet
  2. external package --> style components
  3. direct or inline css in JavaScript
  • Inline CSS Styling in JavaScript using two brackets - {{}} inline css styles

  • Direct CSS on component --> will use for dynamic styling inline css styles

  • Using Style sheet

  • Code from Traversy Media's Github stylesheet copy

  • add classNames to components from stylesheet, added button on Header Component add styles to components

Make Button Component

  • Make Button Component with props, example of reusable components reusable button example
  • adding defaults and PropTypes to button button defaults

EVENTS

  • Intro to setting Events --> 'onClick' button event
  • you can pass in event object to onClick and access position of button along with other properties button event object
  • use onClick event as a prop since Button is a Component button event as prop

State and Tasks

  • Created Array of dummy data for tasks --> loop through information to output creating a list using the map array method
  1. in Tasks.js
  const Tasks = () => {
  return (
    <>
     {tasks.map((task) => (
        <h3>{task.text}</h3> //JSX
      ))} 
    </>
  )
}
  1. in App.js Adding Tasks to App.js
  2. Get warning about key props, parent element (the h3) need to have a key prop --> needs to be unique
const Tasks = () => {
  return (
    <>
     {tasks.map((task) => (
        <h3 key={task.id}>{task.text}</h3>
      ))} 
    </>
  )
}
  1. We don't want the array of tasks to be a separate from our component, we want it to be part of our state --> we are going to use the useState hook to use state inside of a function. Above the return: what you want to call this piece of state, tasks, and function to update state, setTasks, --> set that to useState and paste in default you want to use (in this case the array of tasks)
const Tasks = () => {
  const [tasks, setTasks] = useState([
      {
        id: 1,
        text: 'DMV Alumni Meeting',
        day: 'July 30th at 1pm',
        reminder: true,
      },
      {
        id: 2,
        text: 'Log Coding Hours',
        day: 'August 4th at 4pm',
        reminder: true,
      },
      {
        id: 3,
        text: 'Send Finished Crochet Sweater',
        day: 'August 6th at 11am',
        reminder: false,
      }
    
  ])
  return (
    <>
     {tasks.map((task) => (
        <h3 key={task.id}>{task.text}</h3>
      ))} 
    </>
  )
}
  • State is immutable, can't directly change, so you can't use tasks.push() to add new tasks, if you want to change any part of the state you use setTasks, you recreate it and send it down
  //if you want to spread across what is already there and add a new object
  setTasks([...tasks, {}])
  • Normally you wouldn't have the tasks in the Task component cause we're going to want to access these from other components, use Redux or the Context API, have a store that hovers over your UI that you can pull different pieces of state from
  • We are going to put it in the App.js before the return and make it our global state and pass it down to our components as props
//PASS IT INTO TASK COMPONENT IN APP.JS as PROPS
  return (
    <div className="container">
      <Header />
      <Tasks tasks={tasks} />
    </div>
  );

//PASS IT INTO THE TASKS.JS DESTRUCTURE AS PROPS
const Tasks = ({ tasks }) => {
  return (
    <>
     {tasks.map((task) => (
        <h3 key={task.id}>{task.text}</h3>
      ))} 
    </>
  )
}

Create New Task Component

  • Test by Creating a new Task.js component with generic h3 that will get outputted for every task for now Setting up Task Component
  • use the task prop you added in Tasks.js Use task prop

ADD Delete Icon and Delete Function Prop

  • use font awesome for delete icon and add the CDN into your index.html or install react icons
  1. npm i react-icons --> access to multiple libraries
  2. bring in specific icon FaTimes is the 'x' icon from 'fa' or fontawesome --> import { FaTimes } from 'react-icons/fa' Using react icons
  3. Add style to icon style react icons
  • Using the icon to delete specific task --> with context API or Redux there are ways to access state from within components pretty easily can get complicated with redux and reducers, etc. In this case we can just use props and send down a function as a prop and fire that off when we click on task
  1. In App.js
//DELETE TASK
const deleteTask = (id) => {
  console.log('delete', id);
}

  return (
    <div className="container">
      <Header />
      <Tasks tasks={tasks} onDelete={deleteTask} />
    </div>
  );
}
  1. Pass prop onDelete into Task.js and Tasks.js --> log of id defaults to event info onDelete prop passed in
  2. use in Task.js as function instead for onClick onDelete prop passed in as function
  3. use setState instead of console.log
//DELETE TASK
const deleteTask = (id) => {
  //for each task you want to filter where the task id is not equal to the id
  setTasks(tasks.filter((task) => task.id !== id))
}
  1. set default message for when there are no tasks
  return (
    <div className="container">
      <Header />
      {/* IF THERE ARE TASKS, show Tasks, else show message */}
      {tasks.length > 0 ? <Tasks tasks={tasks} onDelete={deleteTask} /> : 'No Tasks To Show'}
    </div>
  );
  • They will come back when page refreshes since this is the UI and that is what react does, you can turn into full stack app by having back end and have some kind of API you can make requests to and fetch data from --> will try out at end with JSON Server

Add Reminder

  • Want to double click and have a class (in css under .task.reminder) that will change the task to the opposite of whatever is set and if it is true have border
  1. add a reminder toggle in App.js, and pass prop into Tasks
//Toggle Reminder
  const toggleReminder = (id) => {
    console.log(id);
  }

  return (
    <div className="container">
      <Header />
      {/* IF THERE ARE TASKS, show Tasks, else show message */}
      {tasks.length > 0 ? <Tasks tasks={tasks} onDelete={deleteTask} onToggle={toggleReminder} /> : 'No Tasks To Show'}
    </div>
  );
  1. catch the prop in Tasks.js, pass into Task and then add to main div in Task.js Console.log of DoubleClick for toggle
  2. now we want to add logic to toggle reminder from true to false or false to true --> many ways to do this, we are going to use map
   //Toggle Reminder
  const toggleReminder = (id) => {
    //use map to toggle --> map through `tasks` in our state and for each `task` 
    //where `task.id` in current iteration is equal to the id that's passed in 
    //then we have specific object (else the task) 
    //we want to copy && spread across all the task properties and values (of the task that matches) but want to change the reminder so the reminder i'm going to set is opposite of whatever that specific task reminder is
    setTasks(tasks.map((task) => task.id === id ? {...task, reminder: !task.reminder } : task))
  }
  1. Using React Dev Tools --> go to Components react dev tools options
  • now we can see our component tree --> look on App in Tree and check out State react dev tools tree
  • double click on first task and the state changes react dev tools tree after doubleClick
  1. Nothing in UI that lets us know that the state has changed yet, use class of reminder in Task.js to add a border to the edge
  • On className make it into an expression and still want the class task (that will be there no matter what), but add a condition in a template literal, if task.reminder is true then we're going to have the class of reminder, else nothing.
    <div className={`task ${task.reminder ? 'reminder' : ''}`} onDoubleClick={() => onToggle(task.id)}>
      <h3>
        {task.text} 
        <FaTimes 
        style={{color: 'red', cursor: 'pointer'}}
        onClick={() => onDelete(task.id)} 
        />
      </h3>
      <p>{task.day}</p>
    </div>

Now we see border for reminders

  • still goes back to default after refresh because we are just using static data, if we had a back end you'd be making fetch or http requests to your server as well.

ADD Form

  1. Create AddTask.js in Components --> Simple Form to Display for now
  const AddTask = () => {
  return (
    <form className='add-form'>
      <div className='form-control'>
        <label>Task</label>
        <input type='text' placeholder='Add Task' />
      </div>
      <div className='form-control'>
        <label>Day & Time</label>
        <input type='text' placeholder='Add Day & Time' />
      </div>
      <div className='form-control'>
        <label>Set Reminder</label>
        <input type='checkbox'/>
      </div>

      <input type='submit' value='Save Task' />
    </form>
  )
}

export default AddTask
  1. Add to App.js and add some styling on the form from imported CSS by Traversy Media simple form added to UI

Form Input State

  1. each input it going to have it's own piece of component level state NOT app level state, bring in useState and set up for each input with defaults (reminder = false, text and day = '')
import { useState } from 'react'

const AddTask = () => {
  const [text, setText] = useState('')
  const [day, setDay] = useState('')
  const [reminder, setReminder] = useState(false)
  1. In input for text, the value of text is going to be the text from the state but we also need an onChange because when you start to type in the input that's going ot fire off this on change, it's a controlled component, going to have function where we pass in the event object and directly call setText from here and set it to e.target.value which will be whatever is typed in, same for day and setDay
      <div className='form-control'>
        <label>Task</label>
        <input 
          type='text' 
          placeholder='Add Task' 
          value={text}
          onChange={(e) => setText(e.target.value)}
        />
  • for the checkbox use currentTarget.checked --> give us either a true or false value if that is checked or not
  • Look in React-Dev-Tools under AddTask as we can see the state form state
  • you can add in input text an state changes, hit save task and page back to default state right now form state with added text
  1. in App.js add logic for ADD TASK --> it will take in task, and console.log task for now
  //ADD TASK
  const addTask = (task) => {
    console.log(task)
  }
  1. pass it into as prop on AddTask
  return (
    <div className="container">
      <Header />
      <AddTask onAdd={addTask} />
      {/* IF THERE ARE TASKS, show Tasks, else show message */}
      {tasks.length > 0 ? <Tasks tasks={tasks} onDelete={deleteTask} onToggle={toggleReminder} /> : 'No Tasks To Show'}
    </div>
  );
  1. in AddTask.js component we want to take in onAdd and add onSubmit event to form and set that to onSubmit *define onSubmit above return statement, we are not calling onAdd directly
  • onSubmit will take in the event object, we need e.preventDefault() so it does not submit to a page
  • add validation for the task text --> if text is not there, do an alert --> if that passed then we are going to call onAdd and pass in an object with the text, day and reminder
  • then you also want to clear the form so call default state again
  const onSubmit = (e) => {
    e.preventDefault()

    if (!text) {
      alert('Please Add a Task')
      return
    }

    onAdd({ text, day, reminder })

    setText('')
    setDay('')
    setReminder(false)
  }
  • on checkbox reminder, set checked to reminder
      <div className='form-control form-control-check'>
        <label>Set Reminder</label>
        <input 
          type='checkbox'
          checked={reminder}
          value={reminder}
          onChange={(e) => setReminder(e.currentTarget.checked)}
        />
  • Test adding tasks and look in console form data console.log
  1. Instead of console logging we want to add this to our state so in order to do that --> there are a bunch of ways --> since we are not dealing with a back end that creates an id we'll want to add an id to addTask function --> generate random number for id
 //ADD TASK
  const addTask = (task) => {
    const id = Math.floor(Math.random() * 10000) + 1

    console.log(id)
    console.log(task)
  }

console logging id 7. Now we will create new task and add id, plus copy the task text, day and reminder and add to object as well.

  • setTasks as array, copy tasks already there and add new task onto it
  //ADD TASK
  const addTask = (task) => {
    const id = Math.floor(Math.random() * 10000) + 1
    const newTask = {id, ...task}
    setTasks([...tasks, newTask])
  }

add new tasks to UI

Use Add Button to Toggle Add Form

  1. Add new piece of state in the App.js for showAddTask and set to false as default
function App() {
  const [showAddTask, setShowAddTask] = useState(false)
  const [tasks, setTasks] = useState([
  1. embed in in AddTask, wrap in curly braces and say if showAddTask is true then show that component, shorter way of doing a ternary without an else, we just want ot see if it's true, is so do this, if not we do nothing.
  return (
    <div className="container">
      <Header />
      {showAddTask && <AddTask onAdd={addTask} />}
      {/* IF THERE ARE TASKS, show Tasks, else show message */}
      {tasks.length > 0 ? <Tasks tasks={tasks} onDelete={deleteTask} onToggle={toggleReminder} /> : 'No Tasks To Show'}
    </div>
  ); 
  1. Use button to toggle state, we need to do a few things
  • Button is inside the Header --> add prop onAdd and add function to setShowAddTask and we want to set it to whatever the opposite is of the current state
  return (
    <div className="container">
      <Header onAdd={() => setShowAddTask(!showAddTask)} />
      {/* If showAddTask is true we show AddTask else we do nothing */}
      {showAddTask && <AddTask onAdd={addTask} />}
      {/* IF THERE ARE TASKS, show Tasks, else show message */}
      {tasks.length > 0 ? <Tasks tasks={tasks} onDelete={deleteTask} onToggle={toggleReminder} /> : 'No Tasks To Show'}
    </div>
  );
  • Pass into Header.js as prop and change onClick to onAdd and button now toggles the form
const Header = ({ title, onAdd }) => {
  return (
    <header className='header'>
      <h1>{title}</h1>
      <Button color='green' text='Add' onClick={onAdd} />
    </header>
  )
}
  1. Update button style based on state
  • in App.js, in addition to onAdd prop, pass in whatever the value of showAddTask is
  return (
    <div className="container">
      <Header 
        onAdd={() => setShowAddTask(!showAddTask)}
        showAdd={showAddTask} 
      />
  • back in Header.js, pass in showAdd prop and it will be either true or false if it is being shown or not
  • change button text to be dynamic, if showAdd is true then we want to show 'close' else we show 'add', do same for color
  return (
    <header className='header'>
      <h1>{title}</h1>
      <Button 
        color={showAdd ? 'red' : 'green'}  
        text={showAdd ? 'Close' : 'Add'} 
        onClick={onAdd} 
      />
    </header>
  )
  • this is where react is valuable because it allows you to create really dynamic interfaces and no pages are being reloaded or anything like that
  • Vanilla javascript is just very messy and unorganized and much more difficult

Build for Production

  • First how you want to build your static assets out if you are ready to deploy yarn build or npm run build depending on what you are using
  • will create an optimized production build in a folder called build Build for Production
  • this will be our static assets and what we use to deploy where you push to production
  • you want to try this locally you can install the npm package serve globally sudo npm i -g serve --> basic http server
  • now we can serve -s build -p 8000 -p = port
  • SERVING UP APP LOCALLY SERVING UP APP LOCALLY

Using Backend

  1. npm i json-server
  2. create script in package.json to run it, "server": "json-server --watch db.json --port 5000" --> pretend it's a real backend/REST API
  "scripts": {
    "start": "react-scripts start",
    "build": "react-scripts build",
    "test": "react-scripts test",
    "eject": "react-scripts eject",
    "server": "json-server --watch db.json --port 5000"
  },
  1. in terminal npm run server --> creates db.json file with some dummy data we'll delete, we also run our dev server in new terminal as well npm start
  • we want to get data from db.json into dev server --> add tasks from App.js and set state to empty array
  function App() {
  const [showAddTask, setShowAddTask] = useState(false)
  const [tasks, setTasks] = useState([]);
  • update tasks syntax
{
  "tasks": [
    {
      "id": 1,
      "text": "DMV Alumni Meeting",
      "day": "July 30th at 1pm",
      "reminder": true
    },
    {
      "id": 2,
      "text": "Log Coding Hours",
      "day": "August 4th at 4pm",
      "reminder": true
    },
    {
      "id": 3,
      "text": "Send Finished Crochet Sweater",
      "day": "August 6th at 11am",
      "reminder": false
    }
  ]
}
  • json server will automatically create id's on the back end so we won't have to worry about that anymore
  • now we want to fetch the data from the backend
  • if you visit localhost:5000/tasks you will see json of tasks localhost:5000.tasks
  • in order to load them when the page loads we are going to use a hook --> useEffect --> use to create side effects or deal with side effects and if's often used if you want something to happen when the page loads --> it right below were we useState in App.js (also import like useState) --> takes in arrow function and we have to use async within the function itself --> and await the res/promise --> await data response from json --> console.log the data --> and then cal fetchTasks() --> add DEPENDENCY ARRAY at end, we don't have anything to pass in so it's just an empty array
  useEffect(() => {
    const fetchTasks = async () => {
      const res = await fetch('http://localhost:5000/tasks')
      const data = await res.json()

      console.log(data)
    }
    fetchTasks()
  }, []) //DEPENDENCY ARRAY
  • As soon as page loads we are getting our data from our json server which you can replace with any backend console logging data from json
  • we may want to use fetchTasks elsewhere so we are going to define it outside useEffect and instead have function to getTasks that will be async since fetchTasks returns a promise --> fetch tasks from server and await fetchTasks, and then setTasks and add tasks from server, and then call getTasks()
  • Brad has issue with using task.id as key, and changed it to index instead but no issues on my app right now with how it is

Connect Delete Functionality to Server

  • add logic to deleteTask() and make it async (since we'll be awaiting the server) --> don't need to save it as variable since we are not getting any data back --> add second argument of an object where we specify the method of this request to be a delete
  //DELETE TASK
  const deleteTask = async (id) => {
    await fetch(`http://localhost:5000/tasks/${id}`, {
      method: 'DELETE'
    })
    //for each task you want to filter where the task id is not equal to the id
    setTasks(tasks.filter(task => task.id !== id));
  };
  • We can see console log of requests and responses in json server json server requests

Connect Add to Server

  • We want to be able to add a task and have it persist to our backend
  • no longer need to create id in addTask(), because it assigns an id for us --> make function async --> await response/fetch --> route is just (server goes here)/tasks --> with method POST --> add headers since we are adding data and we need to specify our content type (application/json) --> set body(data) that we are sending and set it to JSON.stringify which will turn it from a JS Object to JSON string and what we are sending is the task.
  • then we want to get the data here, data that is return is just the task that is added and then call setTasks again, since it is an array, take existing tasks and then add onto it, data, which is the newTask that was just created
  const addTask = async (task) => {
    const res = await fetch('http://localhost:5000/task', {
      method: 'POST',
      headers: {
        'Content-type' : 'application/json'
      },
      body: JSON.stringify(task)
    })

    const data = res.json()

    setTasks([...tasks, data])
  }
  • NOW I AM GETTING THE KEY ERROR FOR CHILD ELEMENT BRAD GOT BEFORE WITH task.id vs index --> not creating id anymore
  • ALSO NOT WORKING AT THE MOMENT, data in json file but not being served up to UI ERROR
  • we forgot to await the response from json... DEBUGGED

Connect Reminder to DB/SERVER

  • will happen in toggleReminder but first you want to be able to get a single task from the server, copy fetchTasks and change to fetchTask and it's going to take in an id --> and use id in route
  //FETCH TASK
  const fetchTask = async (id) => {
    const res = await fetch(`http://localhost:5000/tasks/${id}`)
    const data = await res.json()

    return data
  }
  • then go down to toggleReminder and we are going to update --> not updating a name but down the same way --> can add if you want
  • create variable to grab task we want to toggle, change to async, and await the task we are fetching, then we put in variable for updated task which is an event and going to have all same properties of taskToToggle and change reminder to whatever the opposite of taskToToggle.reminder is
  • Now we save response to variable, doing update so we will want the id in route, and add method of PUT, add headers since we are sending data and need content type, Json.stringify the body/data
  • then await on response and save to data and in setTasks, data.reminder to set state to updated task data.
    //TOGGLE REMINDER
  const toggleReminder = async (id) => {
    const taskToToggle = await fetchTask(id)
    const updTask = {...taskToToggle, reminder: !taskToToggle.reminder}

    const res = await fetch(`http:localhost:5000/tasks/${id}`, {
      method: 'PUT',
      headers: {
        'Content-type': 'application/json'
      },
      body: JSON.stringify(updTask)
    })

    const data = await res.json()

    setTasks(tasks.map((task) => task.id === id ? {...task, reminder: data.reminder } : task))
  }
  • New Server Logs of Request/Response screenshot of new reminderToggle

ROUTING, FOOTER, and ABOUT

  • Right now everything is in one single page in App.js
  • Can use react-router-dom package to create routes to different pages
  • Create Footer with Link to an About Page
  1. Create Footer.js component
const Footer = () => {
  return (
    <footer>
      <p>Copyright &copy; 2021</p>
      <a href="/about">About</a>
    </footer>
  )
}
  1. import component into App.js and embed it into return Initial set up of Footer
  2. Create About.js component
const About = () => {
  return (
    <div>
      <h4>Version 1.0.0</h4>
      ,<a href="/">Go Back</a>
    </div>
  )
}
  1. Now bring about component into App.js and use router, so import from react-router-dom --> we want to bring in two things BrowserRouter (will use the HTML5 push state) --> give alias as Router and Route
import { useState, useEffect } from 'react';
import { BrowserRouter as Router, Route} from 'react-router-dom'
import Header from './components/Header';
import Footer from './components/Footer';
import Tasks from './components/Tasks';
import AddTask from './components/AddTask'
import About from './components/About'
  1. wrap everything in our return around with <Router> and now that it is wrapped we can use routes, above Footer add in Route and pass in path of '/about' and pass in component
  • right now it still all on one-page, we will need to wrap task and addTask component in it's own route before we give task, and addTask a route
  • But them in an index route'/' we also want to add exact or its going to do the same thing and show the about since it's first going to match the slash, instead of component we can use render, which takes an arrow function with props and point function to a set of parentheses and add a fragment, and add our embedded task an addTask after route is added around embedded task components
  • now see how the page reloads now when we click on about or go back, we want to stop that from happen, instead of using a tag we are going to use link from react-router-dom
  • import into About.js, replace a with Link and href with to
  • Do Same thing in Footer.js --> now both are instant and does not reload the page new Link tags from react-router-dom
  • Get rid of the Add button when you click about, we can go to Header.js and import hook useLocation from react-router-dom
  • allows you to look at the route we are currently on
  • above return create location variable and set to useLocation which gives us access to location.pathname
  • wrap button in curly braces so we can add a condition that if equal to index then show the button
import PropTypes from 'prop-types'
import { useLocation } from 'react-router-dom'
import Button from './Button'

const Header = ({ title, onAdd, showAdd }) => {
  const location = useLocation()


  return (
    <header className='header'>
      <h1>{title}</h1>
      {/* if location.pathname is equal to index then show button */}
      {location.pathname === '/' && ( 
        <Button 
          color={showAdd ? 'red' : 'green'} 
          text={showAdd ? 'Close' : 'Add'} 
          onClick={onAdd} 
        />
      )}
    </header>
  )
}
  • working in app add button shows only on index

About

Follow Along with Traversy Media React Crash Course 2021 https://www.youtube.com/watch?v=w7ejDZ8SWv8