# Modern React and Redux

AirBnB convention (opens new window)

# 1. Dive in

# First Look

App function is a React Component

Component have two jobs.

  1. return JSX
  2. handles events

All components return JSX : instructions that tell React what to show on screen. Looks similar to HTML.

JSX elements

  1. Return HTML element
  2. Return another component

image-20201229205113702

React iterates over every element in JSX.

Check if DOM element. Yes? Show on screen.

No? Call the component function and iterate through it again.

ReactDOM.render(<App />, document.getElementById("root"))
1

First argument : get App function, get JSX, render into HTML

Second argument : Then take the HTML and place it inside the div with this ID in index.html.

The two libraries.

React : Reconciler. Gets components, JSX and iterate through it to make HTML or get more components.

ReactDOM : Renderer. Actually create HTML and put it to DOM.

useState : Works with React's state system. Used to update contents on the screen.

# Generating a React Project

npx create-react-app myapp

npm init react-app my-app

yarn create react-app my-app

# npm vs npx vs yarn

npx allows us to execute it quick.

# What is create-react-app?

Install over 1782 packages. Most importantly, Babel, Webpack and Dev server.

Babel : Since 2015, ES is upgraded and new syntax are made. However, browsers' support for newer ES is poor. Babel changes newer version of ES into largely supported version.

Webpack:

Dev Server :

# Project Directory

image-20201229213027133

# JSX

React works by creating JSX files. Having HTML right inside of JS files. Compiler, which is known as Babel, changes the JSX into a plain Javascript.

image-20210201222245625

d

Babel changes JSX into HTML using React.createElement functions

d

# Template literals = String interpolation

<h1>Hello {`${fName} ${lName}`}</h1>
1

Outer bracket means JS in JSX.

Backtick means template literals, meaning these will be strings.

Inner bracket means JS inside template literals.

# Component

image-20201230163946420

// Import the React and ReactDOM libraries
import React from "react";
import ReactDOM from "react-dom";

// Create a React component
const App = function () {
    return (
        <div>
            <label htmlFor="name" className="label">Enter name:</label>
            <input type="text" id="name" />
            <button style="background-color:blue; color:white;"></button>
      </div>
  )

// Take the React component and show on screen
ReactDOM.render(<App />, document.querySelector("#root"));

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
  • You MUST write component in the same line as return
  • If you don't there will be an error.
  • Common practice is to write parenthesis on the first line.

# Inline styling with JSX

image-20201230164252779

  • Outer parenthesis declares we want to reference JS variable.

  • Second parenthesis declares JS object.

  • Any kebab casing turns into camel casing.

  • value is enclosed with quote marks

  • semicolons are removed and comma is used. Because this is a JS object.

  • Convention demands use double quotes with JSX properties. None JSX property should use single quotes. Lots of companies use double quotes everywhere. Your choice.

# Class with JSX

The keyword 'class' is reserved for JS class in JSX. We have to use className instead. There is a discuss about removing className and just using class because React is becoming smarter.

# JSX can reference JS variables

const App = function () {
  const buttonText = "Click Me!";

  return (
    <div>
      <button>
        {buttonText}
      </button>
    </div>
  );
};
1
2
3
4
5
6
7
8
9
10
11

{buttonText} the parenthesis tells 'I want to use a JS variable'.

Limitation

  • It's ok to put strings, integers, arrays to the JS variable.

  • But if you put object, you will have an error:

    image-20201230170231781

function getButtonText(){
    return 'Click on me!'
}

const App = function () {
  return (
    <div>
      <button>
        {getButtonText()}
      </button>
    </div>
  );
};
1
2
3
4
5
6
7
8
9
10
11
12
13

Function can be used instead as well.

# 3. Communicating with Props

React components are written in 'ReactComponent' style. Not kebab, snake, or camel. Every component in React is independent. It must be exported and imported for 'component nesting'.

// CommentDetail.js
export default CommentDetail;

// index.js
import CommentDetail from './CommentDetail'
<CommentDetail />
1
2
3
4
5
6
  • In relative path, ./ states the current folder.
  • Components don't use curly braces. Treated as JSX tag.
  • Props : System for passing data from a parent component to child component.
// property name = "value"
<CommentDetail author="Coco" />
1
2
const CommentDetail = (props)=>{
    console.log(props)
    //{author:"coco"}
    return(
    	<div>
        	{props.author}
        </div>
    )
}
1
2
3
4
5
6
7
8
9

# html attribute vs react props

image-20210206210524783

image-20210206210533818

attributes are predefined, props are customizable

key is a special property and does not act as props.

# Prop to prop

<ApprovalCard>
    <CommentDetail
        author="Keith"
        time="Today at 15:01"
        content="yeah"
        avatar={faker.image.image()}
        />
</ApprovalCard>

1
2
3
4
5
6
7
8
9
const ApprovalCard = (props)=>{
    return (
    	<div>
        	{props.children}
        </div>
    )
}

1
2
3
4
5
6
7
8
  • You can put prop inside a prop.
  • It will be sent down as props.children. Everything between the tag will be represented as props.childern.

# mapping object to props


const contacts = [
  {
    name: "Beyonce",
    img:
      "https://blackhistorywall.files.wordpress.com/2010/02/picture-device-independent-bitmap-119.jpg",
    phone: "+123 456 789",
    email: "b@beyonce.com"
  },
  {
    name: "Jack Bauer",
    img:
      "https://pbs.twimg.com/profile_images/625247595825246208/X3XLea04_400x400.jpg",
    phone: "+123 456 789",
    email: "jack@nowhere.com"
  },
  {
    name: "Chuck Norris",
    img:
      "https://i.pinimg.com/originals/e3/94/47/e39447de921955826b1e498ccf9a39af.png",
    phone: "+123 456 789",
    email: "gmail@chucknorris.com"
  }
];

const rendered_contacts = contacts.map((contact) => {
  return (
    <Card
      name={contact.name}
      img={contact.img}
      phone={contact.phone}
      email={contact.email}
    />
  );
});

ReactDOM.render(
  <div>{rendered_contacts}</div>)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38

# 4. Structuring Apps with Class-based Components

# React in the Past

  • Functional components used to produce JSX to show content to user.

  • Class components were used to produce JSX to show content to user & use lifecycle method to run code at specific points & use state system to update content on screen

  • Functional components were much more restricted. But now it became more dynamic

    image-20210101120337198

  • Which one should we use?

  • Companies with established projects are using class-based components because this used to be the way.

  • Newer projects use either one.

  • You must understand both.

Learn class-based -> function-based -> redux

# Geolocation API

window.navigator.geolocation.getCurrentPosition(successCallback(){}, failureCallback(){})

    window.navigator.geolocation.getCurrentPosition(
        (position) =>  console.log(position) , 
        (err) => console.log(err)
    )
1
2
3
4
5
6

# Lifecycle of functional component

image-20210101124918561

Getting geolocation service takes some time because it uses API.

Problem is when we get result of geolocation, the screen is already rendered!

There must be a way to 'pause' or 'rerender' the updated part.

Class component must be used to update screen.

# Rule of Class components

  1. Must be a Javascript Class. Different from Ruby or Java's object oriented class inheritance. JS uses prototypal inheritance. But works like class in this case
  2. Must extend React.component
  3. Must define render method that returns JSX
class App extends React.Component{
    render() {
        return <div> Latitude: </div>
    }
}
1
2
3
4
5

When class is made, JS class only has render method. React expects many more methods and these are implemented in React.Component. By using extends we are creating a sub-class.

# State in React Components

Using class component is not enough to rerender updated screen.

  • Understanding state will open new understandings
  • But it is difficult and challenging.

# Rules of state

  1. Only usable with class components. (can be used with functional using the hooks system)

  2. It's confusing with props. Props vs States

  3. State is a JS object that contains data strictly relevant to a component.

  4. Updating state causes rerendering of the componenet.

  5. State must be initialized when component is created.

  6. State can only be updated using the function setState.

# Initializing

class App extends React.Component{
   constructor(props){
       super(props)
       this.state = {lat: null}
   }       
   
    render() {
        return <div> Latitude: {this.state.lat} </div>
    }
}

1
2
3
4
5
6
7
8
9
10
11
  • Constructor is specific to JS not only React. Any time a new instance is created, constructor function is instantly called before anything else. This makes it a good place to initializing state.
  • The super method is called from React.Component. We are replacing the javascript constructor method with react's constructor method. To make sure React.Component's constructor method is called, we state super(props).

# setState

// right way
this.setState({ lat: position.coords.latitude });

// NEVER DO THIS. Only exception is when we initialize.
this.state.lat = position.coords.latitude
1
2
3
4
5
  • this.state direct assignment is only used on initialization

# App lifecycle walkthrough

What happens?

  1. JS file loaded by browser
  2. Instance of App component created
  3. Constructor function gets called. (super needed)
  4. Initialized state object with properties of interest. this.state is a very special name and cannot be named else.
  5. Call async API. The callback function is not executed until some time in the future but the constructor finishes before.
  6. Render method executed.
  7. App returns JSX and rendered to HTML.
  8. API request responsed.
  9. this.setState updates our state
  10. React checks update and runs render method one more time.
  11. Updated JSX returned.
  12. Screen updated.

App component is rendered twice.

# Handling errors (with grace)

For better UX

image-20210101145411837

  render() {
    if (this.state.errorMessage && !this.state.lat) {
      return <div> Error: {this.state.errorMessage} </div>;
    }
    if (!this.state.errorMessage && this.state.lat) {
      return <div>Latitude : {this.state.lat} </div>;
    }

    return <div>Loading!</div>;
  }
1
2
3
4
5
6
7
8
9
10
  • conditional rendering.

# componentDidMount

When I refresh too quick repeatedly, I get

image-20210101150258479

# 6. Lifecycle Methods

We've already seen constructor function. We've also seen render method. Render method is not optional unlike others. Let's see what other methods there are

image-20210101222500747

// Called one time after rendered
componentDidMount(){}

// Called each time updated
componentDidUpdate(){}
1
2
3
4
5

After placing window.navigator.geolocation.getCurrentPosition in the componentDidMount, the error

image-20210101150258479went away.

Do not do dataloading in constructor. setState can only happen to components that are mounted.

# Alternate way to initialize state

constructor(props) {
    super(props);
    this.state = { lat: null, errorMessage: "" };
}

// Same as below. Babel will build up the constructor for us.
state = { lat: null, errorMessage: '' };
1
2
3
4
5
6
7

This makes it simpler. Since constructor method is only used to initialize states, this is a good way to do it.

# Expression vs Statement

An expression evaluates to a value. A statement does something. Statements represent an action or command e.g print statements, assignment statements. Expression is a combination of variables, operations and values that yields a result value.

  • Statement : if switch statements that to conditional stuffs.
  • Expression : simple return value.

# JSX {} can only contain expressions, not statements

function App(){
  return <div>
  {if(isLoggedIn ===true){
    return <h1> Hellow</h1>;
  }else{
          return <Login />
         }}
	</div>
}
1
2
3
4
5
6
7
8
9
  • This does not work because statement is inside {}.

# JS ternary operator(inline condition)

CONDITION ? DO IF TRUE : DO IF FALSE
1
  • By using ternary operator, the if else statement changed into expressions.
//getting the current season

function App(){
  return <div>
    {isLoggedIn === true ? <h1>Hello</h1> : <Login/>}
  </div>
}

1
2
3
4
5
6
7
8

# semantic-ui icons

const icon = season === "winter" ? "snowflake" : "sun";
<i className={`${icon} icon`}></i>
1
2

# configuring options and destructuring

const seasonConfig = {
    summer: {
        text: 'let\'s hit the beach',
        iconName: 'summer'
    },
    winter: {
        text: 'burr it\'s chilly',
        iconName: 'winter'
    }
}

.
.
.


const season = getSeason(props.lat, new Date().getMonth());

//deestructuring
const { text, iconName} = seasonConfig[season]



1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

# importing CSS in React

import './SeasonDisplay.css'
1
  • Webpack will see the the import, and stick it to index.html.

# Default Props

// First way
const AppName = (props)=>{
    return (
        {props.message || 'Loading'}
    )
}


// The beautiful way
AppName.defaultProps = {
    message:"Loading..."
}
1
2
3
4
5
6
7
8
9
10
11
12
  • Great to make reusable elements.

# props combined with ternary expressions

//App.js

import React from "react";
import Form from "./Form";

var userIsRegistered = false;

function App() {
  return (
    <div className="container">
      <Form userIsRegistered={userIsRegistered} />
    </div>
  );
}

export default App;

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
//Form.js

import React from "react";

function Form(props) {
  return (
    <form className="form">
      <input type="text" placeholder="Username" />
      <input type="password" placeholder="Password" />
      {!props.userIsRegistered && (
        <input type="password" placeholder="Confirm Password" />
      )}

      <button type="submit">
        {props.userIsRegistered ? "Login" : "Register"}
      </button>
    </form>
  );
}

export default Form;

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

# Summary of Class Components

image-20210102203406942

image-20210102203425806

image-20210102203502093

+State can only be updated using the function setState

# Clock

    class Clock extends React.Component {
        state ={time:new Date().toLocaleTimeString()}
        
        componentDidMount() {
            setInterval(() => {
                this.setState({time: new Date().toLocaleTimeString()})
            }, 1000)
        }
        
        render() {
            return (
                <div className="time">
                    The time is: {this.state.time}
                </div>
            );
        }
    }

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

# Hoisting

This should be on JS md. Move later

  • Hoisting means getting assigned before it should happen.
console.log(animal)
var animal = "Coco"
console.log(animal)
// Undefined
// Coco

console.log(animal)
let animal = "Coco"
console.log(animal)
// ReferenceError : cannot access before initiaization

1
2
3
4
5
6
7
8
9
10
11
  • In the first case, JS knew that animal would be declared before actually it was. This is called hoisting and happens to var
  • It can also happen to functions.
howl();
function howl(){
    console.log('woof')
}
// woof

hoot();
const hoot = function(){
    console.log('hoo hoo')
}
// ReferenceError : cannot access 'hoot' before initialization

hoot();
var hoot = function(){
    console.log('hoo hoo')
}
console.log(hoot)
// TypeError : hoot is not a function (Type is Undefined)
// (if executed) Undefined

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
  • function declarations are hoisted. These can thought that they are placed on the top of the JS file.
  • function expressions are not hoisted.

# 7. Handling User Input with Forms and Events

# onChange

class SearchBar extends React.Component {
  onInputChange(event) {
    console.log(event.target.value);
  }

  render() {
    return (
      <div>
        <form>
              <input
                type="text"
                onChange={this.onInputChange}
              />
        </form>
      </div>
    );
  }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
  • onChange, onClick and onSubmit are special names.
  • onChange={this.onInputChange} Not onChange={this.onInputChange()} Because we do not want to execute it everytime its rendered. Its a reference of callback function so we can use it sometime in the future.

# onChange alternate: inline arrow function callback

<input type="text" onChange={(event)=>{console.log(event.target.value)}} />
1
  • Can use anonymous arrow function instead of separate function

# Controlled vs Uncontrolled element

What we did before was uncontrolled element. Below is controlled element made by using state.

class SearchBar extends React.Component {
  state = {term:""}


  render() {
    return (
      <div>
        <form>
              <input
                type="text" value = {this.state.term}
                onChange=(e)=>{this.setState({term:e.target.value})}
              />
        </form>
      </div>
    );
  }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
  • state is made and it's synchronized with the input with the value property.
  • Because it uses setState component is rerendered everytime.
  • This is better because information is stored inside the React area not in the html & DOM area.
  • This makes certain manipulations very easy.
    • this.setState({ term: e.target.value.toUpperCase() });

# this

image-20210103164817892

class Car {
  setSound(sound){
    this.sound = sound
  }
  drive(){
    return this.sound;
  }
}

const car = new Car();
car.setSound('vroom')

const truck = {
  sound: 'putput'
  driveMyTruck:car.drive
}

truck.driveMyTruck()
//putput
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
  • driveMyTruck() calls car.drive. car.drive calls this.sound. At this point, although this was car for car, because this is being called from truck, this is assigned to truck.
  • this is not assigned when it's being made but when it's being executed.

# binding this

Legacy way

class Car {
  constructor(){
    this.drive = this.drive.bind(this)
  }
}
1
2
3
4
5

Using arrow function

onFormSubmit(e){
  this.setState({term:e.target.value})
}

// upper is shorthand notation for below

onFormSubmit = function(e){
  this.setState({term:e.target.value})
}

// We can use arrow function
onFormSubmit = (e)=>{
  this.setState({term:e.target.value})
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
  • arrow function do not default this to the window scope, rather they execute in the scope
  • arrow function does not have its own this. The this value of the enclosing lexical scope is used; arrow functions follow the normal variable lookup rules. So while searching for this which is not present in the current scope, an arrow function ends up finding the this from its enclosing scope.

Final method : Using anonymous arrow function inline.

onChange={(e) => {this.setState({ term:e.target.value });
}}
1
2

# Communicating Child to Parent

image-20210104171750154

//App.js

class App extends React.Component {
  onSearchSubmit(term) {
    console.log(term)
  }

  render() {
    return (
      <div>
      	//onSubmit is NOT a specific name. Changable.
        <SearchBar onSubmit={this.onSearchSubmit}/>
      </div>
    );
  }
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
///SearchBar.js
  state = { term: "" };

  onFormSubmit = (event) => {
    event.preventDefault();
    this.props.onSubmit(this.state.term)
  }
1
2
3
4
5
6
7
  • this.props. is used to get the passed down props function.
  • parent function is passed down as props. Searched term is sent to the parent function. Function is run at parent component.

# 8. Making API requests

Sending request to unsplash API

# Axios vs Fetch

yarn add axios

Axios is 3rd party package, and fetch is built into browsers. Axios can be very easily installed using npm. Fetch is far more basic and lower level. You will have to write lot of code that is already written in axios.

Highly recommend to use axios.

// 3rd party import is placed above my components
import React from "react";
import axios from "axios";
import SearchBar from "./SearchBar";

class App extends React.Component {
  onSearchSubmit(term) {
    axios.get(`https://api.unsplash.com/search/photos`, {
      params: { query: term },
      headers: {
        Authorization: "Client-ID kdfkldsljfrMYIDlsjfklsdc",
      },
    });}

1
2
3
4
5
6
7
8
9
10
11
12
13
14

# Request with Async and Await

Two methods. async is newer and better

then()

A promise object is always returned after axios use.then() function to chain. Anytime you are working with promise, you can use then.

axios.get(`https://api.unsplash.com/search/photos`, {
  params: { query: term },
  headers: {
    Authorization: "Client-ID KBHNjiOkkI7vlg-CmyRoIy29kQcZ37eTv0EoC0sgIzc",
  },
})
.then((response) => {
        console.log(response.data.results);;
1
2
3
4
5
6
7
8

async await

state = { images: [] };
async onSearchSubmit(term) {
  const response = await axios.get(`https://api.unsplash.com/search/photos`, {
    params: { query: term },
    headers: {
      Authorization: "Client-ID KBHNjiOkkI7vlg-CmyRoIy29kQcZ37eTv0EoC0sgIzc",
    },
  });
  console.log(response)
  this.setState({ images: response.data.results });
}
1
2
3
4
5
6
7
8
9
10
11

# Binding Callbacks

image-20210108015409881

This error occurs because this in this.state does not point to the App class. It instead points to the props of SearchBar.

onSubmit is sent down to SearchBar component as props. It is then executed via this.props.onSubmit(this.state.term). onSubmit is executed on props so the this directs to the props of SearchBar component.

Refactored as arrow function to fix the this context.

onSearchSubmit = async (term) => {
  const response = await axios.get(`https://api.unsplash.com/search/photos`, {
    params: { query: term },
    headers: {
      Authorization: "Client-ID KBHNjiOkkI7vlg-CmyRoIy29kQcZ37eTv0EoC0sgIzc",
    },
  });
  this.setState({ images: response.data.results });
}

1
2
3
4
5
6
7
8
9
10

# Creating Custom Clients

//unsplash.js

import axios from "axios";

export default axios.create({
  baseURL: "https://api.unsplash.com",
  headers: {
    Authorization: "Client-ID KBHNjMYIDzc",
  },
});

1
2
3
4
5
6
7
8
9
10
11
//App.js
import unsplash from "../api/unsplash";

onSearchSubmit = async (term) => {
  const response = await unsplash.get(`/search/photos`, {
    params: { query: term },
  });
  this.setState({ images: response.data.results });
};
1
2
3
4
5
6
7
8
9

# 9. Building Lists of Records

image-20210108165722545

# map function in javascript

const numbers = [0, 1, 2, 3, 4];

let newNumbers=[]

const new_numbers = numbers.map((num)=>{
	return num * 10
})
1
2
3
4
5
6
7

# Getting lists from props

const ImageList = (props) => {
  const images = props.images.map((image) => {
    return <img src={image.urls.regular} alt={image.alt_description}></img>;
  });
  return <div>{images}</div>;
};
1
2
3
4
5
6

# Keys in props

Purpose

React uses key to identify which list is updated by comparing the keys and the value.

Implementation

<img key={image.id} src={image.urls.regular} alt={image.alt_description} />
1

destructuring

const images = props.images.map((image) => {
  return (
    <img key={image.id} src={image.urls.regular} alt=image.alt_description}
/>
  );
});

// destructured

const images = props.images.map(({id, urls, alt_description}) => {
  return (
    <img key={id} src={urls.regular} alt=alt_description}
/>
  );
});


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

# Accessing the DOM with Refs

image-20210108220559814

Vanila JS : document.querySelector('img').clientHeight

React Refs gives access to a single DOM element. We create refs in the constructor, assign them to instance variables, then pass to a particular JSX element as props.

constructor(props) {
  super(props);
  this.imageRef = React.createRef();
}
.
.
<img ref={this.imageRef} src={urls.regular} alt={description} />
.
.
1
2
3
4
5
6
7
8
9

Listening until images are loaded

componentDidMount() {
  this.imageRef.current.addEventListener("load", this.setSpans);
}
1
2
3

# Redux vs Vuex

Flux libraries are like glasses : you'll know when you need them -Dan Abramov

In the past it was not uncommon to have pieces of state across our application tucked inside of controllers, services, routes, directives (AngularJS), local storage, session storage, cookies, and some other alternatives.

When the application grows, this approach is really hard to scale and this is where Flux and React stepped in.

image-20210108022239362

Flux is the architectural pattern on which the Redux and later Vuex (with some diffs) were based. Flux assumes unidirectional data flow, while MVC is based on bidirectional flow.

An Action consists of action type and eventually action payload, that is the data that will be propagated to the store.

Dispatcher takes an action and dispatches it to a store, which updates themself and propagates a change event to views.

The Store is a “single source of truth” - it’s a global state of our application. It's the central point of the Flux pattern, where data are stored and passed to all components.

View is usually the component

The main difference between them - while Redux uses reducers Vuex uses mutations. In Redux state is always immutable, while in Vuex committing mutation by the store is the only way to change data

React is different from Vue in the way it processes updates: React renders a virtual DOM then calculates optimal DOM operations to make the currently rendered DOM match the new Virtual Dom. But it has no way of knowing whether a particular component needs to re-render or not based on the new data. Vue instances keep track of which bits of data they depend on to render. These instances automatically register what needs to re-render when the data changes.

Last Updated: 3/1/2021, 9:19:08 PM