0% found this document useful (0 votes)
30 views

Miguel Silva - React Curse Part1 in Markdown

Uploaded by

Miguel Silva
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
30 views

Miguel Silva - React Curse Part1 in Markdown

Uploaded by

Miguel Silva
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 96

# The React Bootcamp

## Table of Contents

* [Introduction](#introduction)

* [Setting state with modern JS features](#setting-state-with-modern-js-features)

* [React.Fragment](#react.fragment)

* [Default Props](#default-props)

* [Class default props](#class-default-props)

* [Prop Types](#prop-types)

* [Re-Usability](#re-usability)

* [React Children](#react-children)

* [High Order Components (HOCs)](#high-order-components-hocs)

* [First HOC](#first-high-order-component)

* [Toogle HOC](#toogle-hoc)

* [Render Props](#render-props)

---

## Introduction

What you should already know:

* HTML, CSS, JavaScript

* Introduction to React

* Props

* State

* Forms

* Conditional Rendering

* Functional vs Class Components

What you will learn:

* Miscellaneous intro topics

* Reusability / Patterns
* Performance / Optimization

* Context

* Hooks

* React Router

* Capstone Project

* Redux

* Job Search Advice / Tools

### Setting state with modern JS features

```jsx

import React from 'react'

import NewJSFeatures from './NewES6ClassFeatures'

function App(){

export default App

```

* Use of arrow functions for class methods:

Using them it will automatically adopt **this** from the class where is found. So you can avoid binding
in constructor:

```jsx

this.increment = this.increment.bind(this)

//...

increment = () => {

this.setState(prevState => {

return {

count: prevState.count + 1
}

})

```

* Implicit return in functions

If you return an object you require (). Example:

```jsx

this.setState(prevState => ({count: prevState.count + 1+))

```

* Initalize state as property:

```jsx

class NewJSFeatures extends Componens{

state = {

count: 0,

age: 3

```

* Desconstructuring properties:

```jsx

const {count, age} = this.state

```

So you don't need to use this.state.count everywhere

And you can rename the property:

```jsx

const {count: myCount, age} = this.state


```

so you can use myCount

---

### React.Fragment

As you only can return 1 thing, you often end adding a lot of divs to put your things inside:

```jsx

return(

<div>

<Comp1/>

<Comp2/>

</div>

```

So fragment helps us to don't populate DOM with a lot of unnecesary componentes. So you can use:

```jsx

return(

<React.Fragment>

<Comp1/>

<Comp2/>

</React.Fragment>

```

So at the end this components will render this:

```jsx

<Comp1/>

<Comp2/>

```
instead of:

```jsx

<div>

<Comp1/>

<Comp2/>

</div>

```

Be aware that this will change relations between components (turning most of them in siblings). But
sometimes is necessary to maintain divs for mantain a parent-ship relation.

You can resume Fragment using:

```jsx

import React, {Fragment} from 'react'

```

or you can only use `<>`for React.Fragment. Example:

```jsx

<>

<Comp1/>

<Comp2/>

</>

```

---

### Default Props

It's like default parameters but you declare them differently

If you don't pass a property to a child it will be null.


```jsx

import React from 'react'

function Card(props){

const styles ={

backgroundColor: props.cardColor,

height: 100,

width: 100

return(

<div style={styles}></div>

Card.defaultProps = {

cardColor: "blue"

export default Card;

```

So if you create a Card without passing cardColor property it will use blue

```jsx

<Card cardColor="red" /> // it will use red

<Card /> // it will use blue

```

---

#### Class default props


Is almost the same thing. You also use `Card.defaultProps`

```jsx

import React from "react"

class Card extends React.Component {

render() {

const styles = {

backgroundColor: this.props.cardColor,

height: this.props.height,

width: this.props.width

return (

<div style={styles}></div>

Card.defaultProps = {

cardColor: "blue",

height: 100,

width: 100

export default Card

```

But it's better to specify them as a static attribute:

```jsx
import React from "react"

class Card extends React.Component {

static defaultProps = {

cardColor: "blue",

height: 100,

width: 100

render() {

const styles = {

backgroundColor: this.props.cardColor,

height: this.props.height,

width: this.props.width

return (

<div style={styles}></div>

export default Card

```

---

### Prop Types

[Reference](https://reactjs.org/docs/typechecking-with-proptypes.html#proptypes)

Allows you to specify that incoming props should be of a specific type or to be required.
React put this characteristic in a separate library. So

1. So you need to install prop-types

2. using npm will be:

```powershell

npm install --save prop-types

```

```jsx

import PropTypes from 'prop-types'

function Card(props){

// Note that for the function or class is propTypes not PropTypes

Card.propTypes = {

cardColor: PropTypes.string

```

So this will give you an error:

```jsx

<Card cardColor={42} />

```

These errrs only will be displayed in dev mode. When you build the project to production they will not
show.

Required example:

```jsx

Card.propTypes = {
cardColor: PropTypes.string.isRequired

```

So you will get an error if you miss cardColor prop.

***Note**If you set a prop as required but you have a defaultProp, you won't get a warning.

**Enum example**

```jsx

propName: PropTypes.oneOf(["red", "blue"])

```

**Specify various types**

```jsx

propName: PropTypes.oneOfType([

ProptTypes.string,

PropTypes.number

])

```

==Important==

It's becoming popular to write ReactJS using **TypeScript**, but until you use TypeScript will be useful
to use propTypes

*In React for styles sizes if you only specify a number it will assume that is are pixels

---

## Re-usability

Avoid repetiton
### Re-usability antecedents

**D**on't

**R**epeact

**Y**ourself

2 ways to avoid repeating code:

* Inheritance: OOP

* Composition: divide code in parts that fits together

You should always prefer composition over inheritance

[Video about this](https://www.youtube.com/watch?v=wfMtDGfHWpA&feature=youtu.be)

In the ReactJS, the React team say that

> they always prefer composition instead inheritance to reuse code between componenets

Code re-use patterns:

1. Components w/props

Components are the base unit to re use code

2. Children

3. Higher-order Components

4. Render props

Now with **Hooks** points 3 and 4 are unnecessary. But is still useful to learn them.

---

### React Children


Most of time you use elements in a self closed tag passing props. Ex:

```jsx

<Navbag backgroundColor="firebrick" />

```

Sometimes we just want to create a components that work like wrappers.

Creating a component (CallToAction) that creates a border around the content

```jsx

// CTS.js

import React from "react"

function CTA() {

return (

<div className="border">

<h1>This is an important CTA</h1>

<button>Click me now or you'll miss out!</button>

</div>

export default CTA

```

```css

/* styles in index.html */

.border {

border: 1px solid blue;

border-radius: 5px;

}
```

```jsx

// App.js

import React from "react"

import CTA from "./CTA"

function App() {

return (

<div>

<CTA />

</div>

export default App

```

So I want that style to apply general in all my site.

So any component you create can be used in 2 ways:

```jsx

<CTA />

<CTA></CTA>

```

If you use the second one, all of the elements you put inside CTA will be available on CTA using
`props.children`

Now change App.js to

```jsx

// App.js
import React from "react"

import CTA from "./CTA"

function App() {

return (

<div>

<CTA>

<h1>This is an important CTA</h1>

<button>Click me now or you'll miss out!</button>

</CTA>

</div>

export default App

```

And in CTA just write:

```jsx

// CTS.js

import React from "react"

function CTA() {

return (

<div className="border">

{props.children}

</div>

}
export default CTA

```

So the parent element (CTA) will be responsible of how displaying the components.

So now you can use, CTA with different children and the are always going to have that border around:

```jsx

import React from "react"

import CTA from "./CTA"

function App() {

return (

<div>

<CTA>

<h1>This is an important CTA</h1>

<button>Click me now or you'll miss out!</button>

</CTA>

<CTA>

<form>

<input type="email" placeholder="Enter email address here"/>

<br />

<button>Submit</button>

</form>

</CTA>

</div>

export default App


```

So for example if you need to use a padding in the box, you only have to modify the "border" class and
all the CTA with the childrens will be refreshd.

Also now you have more flexibility in the children. For example in button you can specifiy a function or
props.

You can still using props in the parent:

```jsx

<CTA someProp="value">

<h1>This is an important CTA</h1>

<button>Click me now or you'll miss out!</button>

</CTA>

```

**Rule**

So if you only need to pass data and the structure of the components will always be the same use props.

But if you want to give the user of the component the ability to change the structure, use children

---

### High Order Components (HOCs)

* Stems from the concept of higher-order functions

* A function that takes a component as its first argument and returns a new component that wraps the
given component, providing extra capabilities to it.

High Order Functions

: Functions that take another function as a parameter. Example array.map

It's like a function that takes a component and improves it.


```jsx

const upogradedComponent = withSuperPowers(Component)

export default upgradedcomponent

```

withSuperPowers is the high order component.

It's a convention to start it with **with**

Example:

```jsx

const componentWithToggle = withToggle(Component)

export dfeault componentWithToggle

```

or

```jsx

export default withToggle(Component)

```

add toggle function to a component

This is only an example, these lines won't be so simple.

---

### First High Order component

It's a good practice create a folder HOCs with those elements inside.

This high order component doesn't do anything, is just an example:

```jsx

// withExtraPropAdded.js
import React form 'react'

export function withExtraPropAdded(component){

// just for follow conventions

const Component = component

// returns a functional component

return function(props){

return(

<Component antoherProp="some value" {...props} />

```

```jsx

// App.js

import React from "react"

import {withExtraPropAdded} from "./withExtraPropAdded"

function App(props) {

console.log(props.anotherProp)

// will print "some value"

return (

<div>Hello world!</div>

const AppWithProp = withExtraPropAdded(App)

export default AppWithProp


```

Or at the end:

```jsx

export default withExtraPropAdded(App)

```

Now my App Component was augmented with a prop called `anotherProp`

```jsx

// index.js

RenderDOM.(

<App />,

document.getElementById("root")

```

So in this case in index.js we really are not using App component but instead AppWithProp component

**Note**

If in the high order component you use

```jsx

export function withExtraPropAdded(){

```

In the app.js you have to use:

```jsx

import {withExtraPropAdded} from './withExtraPropAdded'

```

But if you use default

```jsx
export default function withExtraPropAdded(){

```

You can remove curly braces

```jsx

import withExtraPropAdded from './withExtraPropAdded'

```

(See JS modules import and default)

---

### Toogle HOC

As said before HOC's are used to improve or give new habilities to the components.

We have 2 components with similar functionality:

1. Menu

2. Favorite

Both implement a toggle functionality that hide/shows some elements by updating a flag in state:

```jsx

// menu.js

import React, {Component} from "react"

class Menu extends Component {

state = {

show: true

toggleShow = () => {
this.setState(prevState => {

return {

show: !prevState.show

})

render() {

return (

<div>

<button onClick={this.toggleShow}>{this.state.show ? "Hide" : "Show"} Menu </button>

<nav style={{display: this.state.show ? "block" : "none"}}>

<h6>Signed in as Coder123</h6>

<a>Your Profile</a>

<a>Your Repositories</a>

<a>Your Stars</a>

<a>Your Gists</a>

</nav>

</div>

export default Menu

```

```jsx

// favorite.js

import React, {Component} from "react"


class Favorite extends Component {

state = {

isFavorited: false

toggleFavorite = () => {

this.setState(prevState => {

return {

isFavorited: !prevState.isFavorited

})

render() {

return (

<div>

<h3>Click heart to favorite</h3>

<h1>

<span

onClick={this.toggleFavorite}

>

{this.state.isFavorited ? " " : "♡"}

</span>

</h1>

</div>

}
export default Favorite

```

We are going to create a High Order Component that will add toggle functionality to a component

```jsx

// withToggler.js

import React, {Component} from "react"

class Toggler extends Component {

state = {

on: this.props.defaultOnValue

toggle = () => {

this.setState(prevState => {

return {

on: !prevState.on

})

render() {

// Using desconstructuring we can avoid pass unnecesary properties

// (component & defaultOnValue) to Component

const {component: C, defaultOnValue, ...props} = this.props

return (

<C on={this.state.on} toggle={this.toggle} {...props} />

}
export function withToggler(component, optionsObj) {

return function(props) {

return (

<Toggler component={component} defaultOnValue={optionsObj.defaultOnValue} {...props}/>

```

**Note** Its a convention to use **C** for naming the component to avoid having conflicts with the
`import {Component}`

Now favorite.js we can get rid off the toggle logic, and use the toggle functionality provided by props
(toggle & on)

```jsx

// favorite .js

import React, {Component} from 'react'

import {withToggler} from './withToggler'

class Favorite extends Component {

render() {

return (

<div>

<h3>Click heart to favorite</h3>

<h1>

<span

onClick={this.props.toggle}

>
{this.props.on ? " " : "♡"}

</span>

</h1>

</div>

export default withToggler(Favorite, {defaultOnValue: false})

```

Change for menu too

```jsx

// menu.js

import React, {Component} from "react"

import {withToggler} from "./HOCs/withToggler"

class Menu extends Component {

render() {

return (

<div>

<button onClick={this.props.toggle}>{this.props.on ? "Hide" : "Show"} Menu </button>

<nav style={{display: this.props.on ? "block" : "none"}}>

<h6>Signed in as Coder123</h6>

<a>Your Profile</a>

<a>Your Repositories</a>

<a>Your Stars</a>

<a>Your Gists</a>

</nav>
</div>

export default withToggler(Menu, {defaultOnValue: true})

```

*As these new Menu and Favorite components don't use state they can be converted to functional
components

An optionsObj was implemented to allow passing a property defaultOnValue to initalize the visibility of
the toggle

**Note** Currently this re-usability can be achieved more easily using Hooks instead of HOC's

### Render Props

You can pass functions as props in react that return JSX.

the render props pattern allows us to separate the data and logic (like fetching data and setting the
loading state) from the UI (JSX).

Example:

```jsx

// example.js

import React from "react"

function Example(props) {

return (

<div>
{props.render(true)}

</div>

export default Example

```

```jsx

import React from "react"

import Example from "./Example"

function App() {

return (

<div>

<Example render={

function(isDaytime) {

return (

<h1>{isDaytime ? "Good day" : "Good evening"}, Bob!</h1>

}/>

</div>

export default App

```

In this case Example is allowing App component to decide what it wants to render in its place.
So as you can see there is a separation between who handles the UI (App) and who handles de data
(Example).

**Note** difference between functional component and JS function.

They both are JS function. But the difference is that a functional component needs to return some JSX

___

#### Toogle Component using Render Props

If you have to choose between HOC and Render Props, usually is better to choose Render Props.

Instead of passing a component and rendering that component with specific props. We can pass the
component and a function to render it.

We will get rid of the HOC component, and just add Toggler component:

```jsx

// Toggler.js

import React, {Component} from "react"

class Toggler extends Component {

state = {

on: this.props.defaultOnValue

static defaultProps = {

defaultOnValue: false

}
toggle = () => {

this.setState(prevState => ({on: !prevState.on}))

render() {

return (

<div>

{this.props.render({

on: this.state.on,

toggle: this.toggle

})}

</div>

export default Toggler

```

```jsx

// Favorite.js

import React, {Component} from "react"

import Toggler from "./Toggler"

function Favorite(props) {

return (

<Toggler render={

({on, toggle}) => (

<div>

<h3>Click heart to favorite</h3>


<h1>

<span

onClick={toggle}

>

{on ? " " : "♡"}

</span>

</h1>

</div>

}/>

export default Favorite

```

```jsx

// Menu.js

import React from "react"

import Toggler from "./Toggler"

// render the Toggler inside the Menu, and use the render prop to determine what will get displayed

// remember to bring in the "goodies" (state and methods) to that function so you can make this work

function Menu(props) {

return (

<Toggler defaultOnValue={true} render={({on, toggle}) => (

<div>

<button onClick={toggle}>{on ? "Hide" : "Show"} Menu </button>

<nav style={{display: on ? "block" : "none"}}>

<h6>Signed in as Coder123</h6>
<p><a>Your Profile</a></p>

<p><a>Your Repositories</a></p>

<p><a>Your Stars</a></p>

<p><a>Your Gists</a></p>

</nav>

</div>

)}/>

export default Menu

```

It's a good practice that you pass a single object in the render function instead of multiple parameters

A better approach will be:

```jsx

// App.js

import React from "react"

import Menu from "./Menu"

import Favorite from "./Favorite"

import Toggler from "./Toggler"

function App() {

return (

<div>

<Toggler defaultOnValue={true} render={({on, toggle}) => {

return (

<Menu on={on} toggle={toggle}/>

)
}}/>

<hr />

<Favorite />

</div>

export default App

```

```jsx

// Menu.js

import React from "react"

import Toggler from "./Toggler"

// render the Toggler inside the Menu, and use the render prop to determine what will get displayed

// remember to bring in the "goodies" (state and methods) to that function so you can make this work

function Menu(props) {

return (

<div>

<button onClick={props.toggle}>{props.on ? "Hide" : "Show"} Menu </button>

<nav style={{display: props.on ? "block" : "none"}}>

<h6>Signed in as Coder123</h6>

<p><a>Your Profile</a></p>

<p><a>Your Repositories</a></p>

<p><a>Your Stars</a></p>

<p><a>Your Gists</a></p>

</nav>

</div>

)
}

export default Menu

```

##### Functions as children

```jsx

// App.js

import React from "react"

import Menu from "./Menu"

import Favorite from "./Favorite"

import Toggler from "./Toggler"

function App() {

return (

<div>

<Toggler defaultOnValue={true}>

{({on, toggle}) => {

return (

<Menu on={on} toggle={toggle}/>

)}}

</Toggler>

<hr />

<Favorite />

</div>

export default App

```
```jsx

// Toogler.js

import React, {Component} from "react"

class Toggler extends Component {

state = {

on: this.props.defaultOnValue

static defaultProps = {

defaultOnValue: false

toggle = () => {

this.setState(prevState => ({on: !prevState.on}))

render() {

return (

<div>

{this.props.children({

on: this.state.on,

toggle: this.toggle

})}

</div>

}
export default Toggler

```

#### Example fetching data

Fetching data is very common in an application so you can create a DataFetcher that will handle this
task. And the other components will decide what to render with that data.

```jsx

// DataFetcher.js

import React, {Component} from "react"

class DataFetcher extends Component {

state = {

loading: false,

data: null,

error: null

componentDidMount() {

this.setState({loading: true})

fetch(this.props.url)

.then(res => res.json())

.then(data => this.setState({data, loading: false}))

.catch(e => this.setState({error: e, loading: false}))

render() {

const {data, loading, error} = this.state


return (

this.props.children({data, loading, error})

export default DataFetcher

```

```jsx

// App.js

import React from "react"

import DataFetcher from "./DataFetcher"

function App() {

return (

<div>

<DataFetcher url="https://swapi.dev/api/people/1/">

{({data, loading, error}) => (

loading ?

<h1>Loading...</h1> :

error ? "There was an error" : <p>{JSON.stringify(data)}</p>

)}

</DataFetcher>

</div>

export default App

```
----

### React's Tree Rendering

* React recursively renders components down one branch until are no more to render.

* Changes to state or props in any component will recursively re-render down the remaining tree
wheter those components have changed or not

![enter image description here](https://i.ibb.co/f9gkP1S/Captura.png)

If state of App changes all the tree will be re-rendered. This is a decrease in performance

* `shouldComponentUpdate()`, `React.PureComponent`, and `React.memo()` are tools to help fix this


problem

## Performance

### Shallow Comparison

It's like `===` in JS

* same primitive types will be the same. Example

```jsx

console.log("Hi" === "Hi") // true

```

* for objects it will return false if they are not the same reference:

```jsx

console.log({} === {}) // false

```
**Note** In JS objects are passed by reference, and primitive values are passed by value.

A shallow comparison realize a comparisson betwwen each key and property between 2 objets. It's like
using the === in each key and value of the 2 objects

So:

```jsx

const state = {

favNumber: 42,

name: "Bob"

const state2 = {

favNumber: 42,

name: "Bob"

```

A shallow comparison between state and state2 will be true. It's like:

```jsx

console.log(state.favNumber === state2.favNumber) // true

console.log(state.name === state2.name) // true

```

So both objects are shallowly equal

But if we have:

```jsx

const state = {

favNumber: 42,
name: "Bob",

address: {

street: "123 Main Street",

city: "Nowhere, PA",

zip: 12345

const state2 = {

favNumber: 42,

name: "Bob",

address: {

street: "123 Main Street",

city: "Nowhere, PA",

zip: 12345

```

They are not going t be shallowly equal

```jsx

const person = {

name: "Sarah"

console.log(anotherPerson === person) // true

```

#### In arrays

```jsx
const arr1 = [1, 2, 3]

const arr2 = [1, 2, 3]

```

both arrays will be shallow equal because the === comparison between each index and value is the
same.

But using `arr1 === ar2` in JSX will be **false**

```jsx

const arr1 = [1, 2, 3, [4]]

const arr2 = [1, 2, 3, [4]]

```

Now they are not shallow equal

---

### shouldCompoenntUpdate

You usally won't use this method

* Lifecycle method on class components

* Allows you to determine if a component should update or not

* Receives the upcoming props and state so you can compare them against current props and state

* return **true** or **false** to indicate if it has to update

* Don't do deep equality checks in here (recommendation by ReactJS) because it's going to be inefficient

Before improving performance:

Components:

* App

* GrandParent

* Parent
* Child

* Grand Child

```

>[GP] [P] [C] [GC] APP just rendered

>[ ] [ ] [ ] [ ] rendered

>[ ] [ ] [ ] [ ] rendered

>[ ] [ ] [ ] [ ] rendered

>[ ] [ ] [ ] [ ] rendered

>[ ] [ ] [ ] [ ] rendered

>[ ] [ ] [ ] [ ] rendered

>[ ] [ ] [ ] [ ] rendered

>[ ] [ ] [ ] [ ] rendered

>[ ] [ ] [ ] [ ] rendered

>[ ] [ ] [ ] [ ] rendered

>[ ] [ ] [ ] [ ] rendered

>[ ] [ ] [ ] [ ] rendered

>[ ] [ ] [ ] [ ] rendered

>[ ] [ ] [ ] [ ] rendered

>[ ] [ ] [ ] [ ] rendered

>[ ] [ ] [ ] [ ] rendered

>[ ] [ ] [ ] [ ] rendered

>[ ] [ ] [ ] [ ] rendered

>[ ] [ ] [ ] [ ] rendered

>[ ] [ ] [ ] [ ] rendered

>[ ] [ ] [ ] [ ] rendered

>[ ] [ ] [ ] [ ] rendered

>[ ] [ ] [ ] [ ] rendered
>[ ] [ ] [ ] [ ] rendered

>[ ] [ ] [ ] [ ] rendered

>[ ] [ ] [ ] [ ] rendered

>[ ] [ ] [ ] [ ] rendered

>[ ] [ ] [ ] [ ] rendered

>[ ] [ ] [ ] [ ] rendered

>[ ] [ ] [ ] [ ] rendered

```

```jsx

// GrandParent.js

import React, {Component} from "react"

import Parent from "./Parent"

class GrandParent extends Component {

shouldComponentUpdate(nextProps, nextState) {

if (nextProps.count === this.props.count) {

return false

return true

render() {

console.log("[ ] [ ] [ ] [ ] rendered")

return (

<div>

<p>I'm a GrandParent Component</p>

<Parent />

<Parent />
</div>

export default GrandParent

```

initial render will render everything. But when we change state in App it won't re render GrandParent

In JS `null === null` is **true**

The disadventage in using *shouldComponentUpdate* is that you will need to loop in each key => value
to test if there was a change.

So for that reason ReactJS created PureComponent for using it instead of Component

---

### React.PureComponent

ReactJS recommends React.PureComponent instead of *shouldComponentUpdate*

* Alternative to React.Component

* Automatically implements *shouldComponentUpdate()* for shallow props and state comparisons

* Disallows using *shouldComponentUpdate()* manually

* Skips rendering all children in the tree automatically, so they must be "pure" as well

* Generally prefered against shouldComponentUpdate()*

**Note** Pure Component doesn't allow you to specify something as `shouldComponentUpdate()`

So in GrandParent:
```jsx

// GrandParent.js

import React, {PureComponent} from "react"

import Parent from "./Parent"

class GrandParent extends PureComponent {

render() {

console.log("[ ] [ ] [ ] [ ] rendered")

return (

<div>

<p>I'm a GrandParent Component</p>

<Parent />

<Parent />

</div>

export default GrandParent

```

So as before, initial render will render everything. But when we change state in App it won't re render
GrandParent.

We don't need to know what props we are receiving because they all are being compared automatically

If in App.js we use:

```jsx

<GrandParent count={this.state.count} />

<GrandParent />
```

So one entire branch of GrandParent and all it's children will be updated when App state change and the
other not.

==Important== Things are currently moving to use functional components instead of class based.

### React.memo

* Higher-order component built by React (released in v16.6)

* Pretty much the same as PureComponent, but for functional components

* It only compares prevProps and nextProps (no state checking)

* You can optionally implement your own checking function (called `areEqual`) to determine if it should
use the memoized result

* This function is kind of like shouldComponentUpdate(), except it should return true if the
props are equal and false if they aren't. This is effectively the opposite approach of
shouldComponentUpdate(), which returns true if the component should re-render (i.e. props are
different)

Example of use:

```jsx

// GrandParent.js

import React from "react"

import Parent from "./Parent"

function GrandParent(props) {

console.log("[ ] [ ] [ ] [ ] rendered")

return (

<div>

<p>I'm a GrandParent Component</p>

<Parent />
<Parent />

</div>

export default React.memo(GrandParent)

```

So React is going to cach the data of the component and then compare the new props to see if there's a
difference with the previous ones.

You can also write:

```jsx

import React, {memo} from "react"

import Child from "./Child"

export default memo(function Parent() {

console.log("[ ] [ ] [ ] [ ] rendered")

return (

<div>

<p>I'm a Parent Component</p>

<Child />

<Child />

</div>

})

```

#### areEqual

```jsx
function areEual(prevProps, nextProps){

export default React.memo(Parent, areEqual)

```

When you use the HOC memo you have to pass your specific areEqual function

Don't spend a lot of effort in optimization. If your app is not presenting performance issues maybe you
don't need to use this.

## React Context

[React Context Reference](https://reactjs.org/docs/context.html)

In ReactJS you only can pass data downwards using props.

If you need to pass it to siblings, you need to up your data up to the parent. So at the end you always
need to have a parent in common to pass data.

This is called `prop dealing`

![enter image description here](https://i.ibb.co/fXmWMPj/Captura.png)

This problem can be solved using **Context**

Context

: provides a way to pass data thourhg the coponent tree without having to pass props down manually at
every level

For example if we need to display data in 3 separated components (*consumers*).


We need to find a common parent, that will act as *provider* and will create a direct tunnel to the
*consumers*

Usually you pass data and a method to modify that data (and the provider will update that data to the
other consumers)

Context has a similar use than Redux

### Implementation

Use createContext through react package

```jsx

// ThemeContext.js

import React from "react"

const ThemeContext = React.createContext()

// ThemeContext.Provider & ThemeContext.Consumer

export default ThemeContext

```

```jsx

// index.js

import React from "react"

import ReactDOM from "react-dom"

import App from "./App"

import ThemeContext from "./themeContext"

ReactDOM.render(

<ThemeContext.Provider value={"light"}>

<App />
</ThemeContext.Provider>,

document.getElementById("root")

```

value is the mandatory prop with the data we want to pass

Suposs that App contains Header

and Header contains Button component

```jsx

// Button.js

import React, {Component} from "react"

import ThemeContext from "./themeContext"

class Button extends Component {

render() {

const theme = this.context

return (

<button className={`${theme}-theme`}>Switch Theme</button>

Button.contextType = ThemeContext

export default Button

```

this.context will contain the data specified in ThemeContext


You can also specific contextType as a static property in the class:

```jsx

import React, {Component} from "react"

import ThemeContext from "./themeContext"

class Header extends Component {

static contextType = ThemeContext

render() {

const theme = this.context

return (

<header className={`${theme}-theme`}>

<h2>{theme === "light" ? "Light" : "Dark"} Theme</h2>

</header>

export default Header

```

contextType is limited , it only can be used in class and it doesn't allow to specify a method to change
the data.

It only allows to consume the data.

---

#### Example2

```jsx

// userContext.js
import React from "react"

const UserContext = React.createContext()

export default UserContext

```

```jsx

// index.js

import React from "react"

import ReactDOM from "react-dom"

import App from "./App"

import UserContext from "./userContext"

ReactDOM.render(

<UserContext.Provider value={"bobz123"}>

<App />

</UserContext.Provider>,

document.getElementById("root")

```

```jsx

// App.js

import React from "react"

import Header from "./Header"

import UserContext from "./userContext"

class App extends React.Component {


static contextType = UserContext

render() {

const username = this.context

return (

<div>

<Header />

<main>

<p className="main">No new notifications, {username}! </p>

</main>

</div>

export default App

```

```jsx

// Header.js

import React, {Component} from "react"

import UserContext from "./userContext"

class Header extends Component {

static contextType = UserContext

render() {

const username = this.context

return (

<header>
<p>Welcome, {username}!</p>

</header>

export default Header

```

### Context.Consumer

Using Context.Consumer you can receive context in a functional component

```jsx

// Button.js

import React from "react"

import ThemeContext from "./themeContext"

function Button(props) {

return (

<ThemeContext.Consumer>

// It's like Render props

{theme => (

<button className={`${theme}-theme`}>Switch Theme</button>

)}

</ThemeContext.Consumer>

export default Button


```

The function you pass inside Consumer is going to receive the data that is passed by the provider.

The provider was used wrapping the App to be able to pass the value in any part of the application.

A better approach to button:

To allow that button is not going always to use the theme:

```jsx

// Button.js

import React from "react"

import ThemeContext from "./themeContext"

function Button(props) {

return (

<button className={`${props.theme}-theme`}>Switch Theme</button>

// Extra adding deafult and types:

Button.propTypes = {

theme: PropTypes.oneOf(["light", "dark"])

Button.defaultProps = {

theme: "light"
}

export default Button

```

```jsx

import React from "react"

import Header from "./Header"

import Button from "./Button"

import ThemeContext from "./themeContext"

function App() {

return (

<div>

<Header />

<ThemeContext.Consumer>

{theme => (

<Button theme={theme} />

)}

</ThemeContext.Consumer>

<Button theme="light" />

</div>

export default App

```
In this way you can choose which buttons are going to use the context and which not.

### Move Context Provider to its own component

In order to be able to change the data in provider, we will create provider in it's own component to
manage state

```jsx

// themeContext.js

import React, {Component} from "react"

const {Provider, Consumer} = React.createContext()

class ThemeContextProvider extends Component {

render() {

return (

<Provider value={"light"}>

{this.props.children}

</Provider>

export {ThemeContextProvider, Consumer as ThemeContextConsumer}

```

```jsx

// index.js

import React from "react"

import ReactDOM from "react-dom"


import App from "./App"

import {ThemeContextProvider} from "./themeContext"

ReactDOM.render(

<ThemeContextProvider value={"light"}>

<App />

</ThemeContextProvider>,

document.getElementById("root")

```

```jsx

// Header.js

import React, {Component} from "react"

import {ThemeContextConsumer} from "./themeContext"

function Header(props) {

return (

<ThemeContextConsumer>

{theme => (

<header className={`${theme}-theme`}>

<h2>{theme === "light" ? "Light" : "Dark"} Theme</h2>

</header>

)}

</ThemeContextConsumer>

export default Header


```

Benefits:

* We are no importing the themeContext directly in index.js

* There is no implementation details in index.js

Another benefit in this approach is that will allow us to pass a method to change the data. That will be
seen in the next lesson:

### Changing context

```jsx

import React, {Component} from "react"

const {Provider, Consumer} = React.createContext()

class ThemeContextProvider extends Component {

state = {

theme: "light"

toggleTheme = () => {

this.setState(prevState => {

return {

theme: prevState.theme === "light" ? "dark" : "light"

})

render() {

return (

<Provider value={{theme: this.state.theme, toggleTheme: this.toggleTheme}}>


{this.props.children}

</Provider>

export {ThemeContextProvider, Consumer as ThemeContextConsumer}

```

Now provider provides a method to change the theme

```jsx

// Button.js

import React from "react"

import {ThemeContextConsumer} from "./themeContext"

function Button(props) {

return (

<ThemeContextConsumer>

{context => (

<button onClick={context.toggleTheme} className={`${context.theme}-theme`}>Switch


Theme</button>

)}

</ThemeContextConsumer>

export default Button

```

So clicking the button all the consumers that take the theme value will be updated
### Chanllege: Context Practice 3

[Controlled Components Reference](https://reactjs.org/docs/forms.html#controlled-components)

Controlled Components (use forms) for now need to be written in class components

```jsx

// Usercontext.js

import React from "react"

const {Provider, Consumer} = React.createContext()

class UserContextProvider extends React.Component {

state = {

username: "bob123"

changeUsername = (username) => {

this.setState({username})

render() {

const {username} = this.state

return (

<Provider value={{username, changeUsername: this.changeUsername}}>

{this.props.children}

</Provider>

}
export {UserContextProvider, Consumer as UserContextConsumer}

```

```jsx

// index.js

import React from "react"

import ReactDOM from "react-dom"

import App from "./App"

import {UserContextProvider} from "./userContext"

ReactDOM.render(

<UserContextProvider>

<App />

</UserContextProvider>,

document.getElementById("root")

```

```jsx

// Header.js

import React from "react"

import {UserContextConsumer} from "./userContext"

function Header() {

return (

<header>

<UserContextConsumer>

{({username}) => (

<p>Welcome, {username}!</p>
)}

</UserContextConsumer>

</header>

export default Header

```

```jsx

// App.js

import React from "react"

import Header from "./Header"

import {UserContextConsumer} from "./userContext"

class App extends React.Component {

state = {

newUsername: ""

handleChange = (e) => {

const {name, value} = e.target

this.setState({[name]: value})

render() {

return (

<div>

<Header />
<UserContextConsumer>

{({username, changeUsername}) => (

<main>

<p className="main">No new notifications, {username}! </p>

<input

type="text"

name="newUsername"

placeholder="New username"

value={this.state.newUsername}

onChange={this.handleChange}

/>

<button onClick={() => changeUsername(this.state.newUsername)}>Change


Username</button>

</main>

)}

</UserContextConsumer>

</div>

export default App

```

### Context Conclusion

Caveats:

* Don't use context just to avoid prop drilling a layer or 2 down

* React suggests not using it to avoid prop drilling at all in certain circumstances ([Before you
Use Context](https://reactjs.org/docs/context.html#before-you-use-context))

* Don't use context for state that should just be kept locally (e.g. forms)
* Context is not a replace for state

* Wrap the Provider around the lowest common parent in the tree

* (it means choosing the deeper parent for the childs that need that data)

* Passing object as value, watch performance and refactor if necessary.

* Because for the way objets are passed (by reference). The consumer are going to be refreshed
even if the values in the object are the same

* [Caveats](https://reactjs.org/docs/context.html#caveats) from React Context Docs

* [React Context and Re-Renders: Take the


Wheel](https://medium.com/@ryanflorence/react-context-and-re-renders-react-take-the-wheel-
cd1d20663647) by Ryan Florence

---

## React Hooks

### React Hooks intro

Tendency in ReactJS is to use functional components.

Before we usually follow this: *use functional component first, but use classes if you need to manage
state or life cycle methods*

* "Hook into" state and lifecycle methods of components without using classes.

* Only use functional components across the board.

* Improve readability and organization of components.

* Create custom hooks to reuse code across your app

There are still 2 life cycle methods that are not available in hooks:

* getSnapshotBeforeUpdate()

* componentDidCatch()

But they are very uncommon


#### List of Hooks

* useState

* useEffect

* useContext

* useRef

* useReducer

* useMemo

* useCallback

* useImperativeHandle

* useLayoutEeffect

* useDebugValue

We will focus on the first 5

You need to be aware because using useMemo and useCallback for improving performance sometimes
can be good.

### useState

```jsx

import React, {useState} from 'react'

function App(){

const [count, setCount] = useState(0)

function increment(){

setCount(prevCount => prevCount + 1)

return(
<div>

<h1>{count}</h1>

<button onClick={increment}>Increment</button>

</div>

export default App

```

There is a convention that if I name the first count, the second is setCount.

==**IMPORTANT**==

In class based components, when you use setState you can specify only the values you are changing. But
using functional components and useState hook, you have to specify all the properties in setState.

A solution is that you can use object deconstructing:

```jsx

setState(prevState => {

count: 0,

...prevState // rest of properties

```

Or you can useState for different properties:

```jsx

const [count, setCount] = useState(0)

const [answer, setAnswer] = useState("Yes")

```

---
### Changing more complex state

==Important==

Apparently everytime the state in a component changes, the component is re-rendered (if it's a class
based) or is called again if it's a function.

```jsx

import React, {useState} from "react"

function App() {

const [inputData, setInputData] = useState({firstName: "", lastName: ""})

const [contactsData, setContactsData] = useState([])

function handleChange(event) {

const {name, value} = event.target

setInputData(prevInputData => ({...prevInputData, [name]: value}))

function handleSubmit(event) {

event.preventDefault()

setContactsData(prevContacts => [...prevContacts, inputData])

const contacts = contactsData.map(contact => <h2 key={contact.firstName +


contact.lastName}>{contact.firstName} {contact.lastName}</h2>)

return (

<>

<form onSubmit={handleSubmit}>

<input
placeholder="First Name"

name="firstName"

value={inputData.firstName}

onChange={handleChange}

/>

<input

placeholder="Last Name"

name="lastName"

value={inputData.lastName}

onChange={handleChange}

/>

<br />

<button>Add contact</button>

</form>

{contacts}

</>

export default App

```

---

### useEffect

You can replace 3 life cycle methods:

* componentDidMount

* componentDidUpdate

* componentWillUnmount

Example of uses:
* Network request

* Event listeners or timeous and intervals

* Manual DOM manipulation

Simulate componentDidUpdate to do something when state changes:

```jsx

import React, {useState, useEffect} from "react"

import randomcolor from "randomcolor"

function App() {

const [count, setCount] = useState(0)

const [color, setColor] = useState("")

function increment() {

setCount(prevCount => prevCount + 1)

function decrement() {

setCount(prevCount => prevCount - 1)

useEffect(() => {

setColor(randomcolor())

}, [count])

return (

<div>

<h1 style={{color: color}}>{count}</h1>


<button onClick={increment}>Increment</button>

<button onClick={decrement}>Decrement</button>

</div>

export default App

```

the second parameter in useEffect is an array of variables to watch for changes

Simulating componentDidMount:

```jsx

useEffect(() => {

setColor(randomcolor())

}, [])

```

Simulating `componentWillUnmount`:

```jsx

useEffect(() => {

const intervalId = setInterval(() => {

setCount(prevCount => prevCount + 1)

}, 1000)

// clean up function

return () => clearInterval(intervalId)

}, [])

useEffect(() => {
setColor(randomcolor())

}, [count])

```

Returning a function in useEffect is what creates the componentWillUnmount effect

So ReactJS run useEffect and stores the function that receives. And when the component get's
unmounted ReactJS run that function.

---

### Speed Typing Game Part1 to 6

Is not recommended the use of setInterval in ReactJS, is better to use setTimeout

Game countdown:

```jsx

useEffect(() => {

setTimeout(() => {

setTimeRemaining(time => time - 1)

}, 1000)

}, [timeRemaining])

```

Use effect will run the first time the component is mount. And after there will be called every second,
because every second we are changing timeRemaining that keeps tracked.

Try to leave your events in forms calling a method if they get too many statements

Code:

```jsx
import React, {useState, useEffect} from "react"

/**

* Challenge:

* When the timer reaches 0, count the number of words the user typed in

* and display it in the "Word count" section

* After the game ends, make it so the user can click the Start button again

* to play a second time

*/

function App() {

const STARTING_TIME = 5

const [text, setText] = useState("")

const [timeRemaining, setTimeRemaining] = useState(STARTING_TIME)

const [isTimeRunning, setIsTimeRunning] = useState(false)

const [wordCount, setWordCount] = useState(0)

function handleChange(e) {

const {value} = e.target

setText(value)

function calculateWordCount(text) {

const wordsArr = text.trim().split(" ")

return wordsArr.filter(word => word !== "").length

}
function startGame() {

setIsTimeRunning(true)

setTimeRemaining(STARTING_TIME)

setText("")

function endGame() {

setIsTimeRunning(false)

setWordCount(calculateWordCount(text))

// https://www.google.com/search?q=Disable+button+in+react

useEffect(() => {

if(isTimeRunning && timeRemaining > 0) {

setTimeout(() => {

setTimeRemaining(time => time - 1)

}, 1000)

} else if(timeRemaining === 0) {

endGame()

}, [timeRemaining, isTimeRunning])

return (

<div>

<h1>How fast do you type?</h1>

<textarea

onChange={handleChange}
value={text}

disabled={!isTimeRunning}

/>

<h4>Time remaining: {timeRemaining}</h4>

<button

onClick={startGame}

disabled={isTimeRunning}

>

Start

</button>

<h1>Word count: {wordCount}</h1>

</div>

export default App

```

---

### useReef

Allows to grab a DOM element. Equivalent to document.getElementById

The reason you cannot use getElementByid is because as components can be reused you are going to
have duplicate id's.

**Note** Remember that using forms in the method you use to submit the form you have to use
event.preventDefault() to prevent the form submitting.

**Note2** When a button is inside a form, pressing enter will automatically press the button
React automatically adds a property called ref in inputs

```jsx

const inputRef = useRef(null)

// ...

<input ref={inputRef} />

```

You can access the element with inputRef.current

Example:

Allowing that every time I press enter the focus return to input:

```jsx

import React, {useState, useRef} from "react"

function App() {

const [newTodoValue, setNewTodoValue] = useState("")

const [todosList, setTodosList] = useState([])

const inputRef = useRef(null)

function handleChange(event) {

setNewTodoValue(event.target.value)

function addTodo(event) {

event.preventDefault()

setTodosList(prevTodosList => [...prevTodosList, newTodoValue])

setNewTodoValue("")
inputRef.current.focus()

const allTodos = todosList.map(todo => <p key={todo}>{todo}</p>)

return (

<div>

<form>

<input ref={inputRef} type="text" name="todo" value={newTodoValue}


onChange={handleChange}/>

<button onClick={addTodo}>Add todo item</button>

</form>

{allTodos}

</div>

export default App

```

### Speed Typing Game Part7

==Important==

React changes states asynchronously, so if I have:

```jsx

setState(count => count + 1)

action2()

```

The first line is done asynchronously so ReactJS is not going to wait until the state is changed to do
action2
Addition of focus:

```jsx

import React, {useState, useEffect, useRef} from "react"

/**

* Challenge:

* Make the input box focus (DOM elements have a method called .focus())

* immediately when the game starts

*/

function App() {

const STARTING_TIME = 5

const [text, setText] = useState("")

const [timeRemaining, setTimeRemaining] = useState(STARTING_TIME)

const [isTimeRunning, setIsTimeRunning] = useState(false)

const [wordCount, setWordCount] = useState(0)

const textBoxRef = useRef(null)

function handleChange(e) {

const {value} = e.target

setText(value)

function calculateWordCount(text) {

const wordsArr = text.trim().split(" ")

return wordsArr.filter(word => word !== "").length

}
function startGame() {

setIsTimeRunning(true)

setTimeRemaining(STARTING_TIME)

setText("")

textBoxRef.current.disabled = false

textBoxRef.current.focus()

function endGame() {

setIsTimeRunning(false)

setWordCount(calculateWordCount(text))

useEffect(() => {

if(isTimeRunning && timeRemaining > 0) {

setTimeout(() => {

setTimeRemaining(time => time - 1)

}, 1000)

} else if(timeRemaining === 0) {

endGame()

}, [timeRemaining, isTimeRunning])

return (

<div>

<h1>How fast do you type?</h1>

<textarea

ref={textBoxRef}
onChange={handleChange}

value={text}

disabled={!isTimeRunning}

/>

<h4>Time remaining: {timeRemaining}</h4>

<button

onClick={startGame}

disabled={isTimeRunning}

>

Start

</button>

<h1>Word count: {wordCount}</h1>

</div>

export default App

```

---

### useContext

(Using example from React Context topic)

It will help us to do that case easier

```jsx

use {useContext} from 'react'

cont context = useContext(fullContextObj)

```
exporting consumer won't be necessary

```jsx

// themeContext.js

import React, {Component} from "react"

const ThemeContext = React.createContext()

class ThemeContextProvider extends Component {

state = {

theme: "dark"

toggleTheme = () => {

this.setState(prevState => {

return {

theme: prevState.theme === "light" ? "dark" : "light"

})

render() {

return (

<ThemeContext.Provider value={{theme: this.state.theme, toggleTheme: this.toggleTheme}}>

{this.props.children}

</ThemeContext.Provider>

}
export {ThemeContextProvider, ThemeContext}

```

```jsx

// index.js

import React from "react"

import ReactDOM from "react-dom"

import App from "./App"

import {ThemeContextProvider} from "./themeContext"

ReactDOM.render(

<ThemeContextProvider>

<App />

</ThemeContextProvider>,

document.getElementById("root")

```

```jsx

// App.js

import React from "react"

import Header from "./Header"

import Button from "./Button"

function App() {

return (

<div>

<Header />
<Button />

</div>

export default App

```

```jsx

// Button.js

import React, {useContext} from "react"

import {ThemeContext} from "./themeContext"

function Button(props) {

const context = useContext(ThemeContext)

return (

<button

onClick={context.toggleTheme}

className={`${context.theme}-theme`}

>

Switch Theme

</button>

export default Button

```

```jsx
// Header.js

import React, {useContext} from "react"

import {ThemeContext} from "./themeContext"

function Header(props) {

const {theme} = useContext(ThemeContext)

return (

<header className={`${theme}-theme`}>

<h2>{theme === "light" ? "Light" : "Dark"} Theme</h2>

</header>

export default Header

```

---

### Hooks Practice - reafactor themeContext

Covnerting theme.Context.js to a functional component:

Before:

```jsx

// themeContext.js

import React, {Component} from "react"

const ThemeContext = React.createContext()

class ThemeContextProvider extends Component {

state = {

theme: "dark"
}

toggleTheme = () => {

this.setState(prevState => {

return {

theme: prevState.theme === "light" ? "dark" : "light"

})

render() {

return (

<ThemeContext.Provider value={{theme: this.state.theme, toggleTheme: this.toggleTheme}}>

{this.props.children}

</ThemeContext.Provider>

export {ThemeContextProvider, ThemeContext}

```

After:

```jsx

import React, {useState} from "react"

const ThemeContext = React.createContext()

function ThemeContextProvider(props) {

const [theme, setTheme] = useState("dark")


function toggleTheme() {

setTheme(prevTheme => prevTheme === "light" ? "dark" : "light")

return (

<ThemeContext.Provider value={{theme, toggleTheme}}>

{props.children}

</ThemeContext.Provider>

export {ThemeContextProvider, ThemeContext}

```

---

#### Another example of function vs class component

Before:

```jsx

import React, {Component} from "react"

class App extends Component {

state = {

count: 0

increment = () => {

this.setState(prevState => ({count: prevState.count + 1}))

render() {
return (

<div>

<h1>The count is {this.state.count}</h1>

<button onClick={this.increment}>Add 1</button>

</div>

export default App

```

After:

```jsx

import React, {useState} from "react"

function App(props){

const [count, setCount] = useState(0)

function increment(){

setCount(prevCount => prevCount + 1)

return (

<div>

<h1>The count is {count}</h1>

<button onClick={increment}>Add 1</button>

</div>

)
}

export default App

```

### Custom Hooks

Before we talked about 3 re-usability techniques:

* React children (this.props.children)

* HOC's

* Render Props

Custom Hooks allow us to simplify more re-usability

We are going to modify the next example of a counter:

```jsx

import React, {useState} from "react"

function App() {

const [count, setCount] = useState(0)

function increment() {

setCount(prevCount => prevCount + 1)

return (

<div>

<h1>The count is {count}</h1>

<button onClick={increment}>Add 1</button>

</div>

)
}

export default App

```

So for example if we want to implement that count logic in another components, we could use HOC's or
render props to do that.

But the easist way is using a Custom Hook:

As we are not going to use JSX we are not importing React

```jsx

// useCounter.js

import {useState} from "react"

function useCounter(){

// initialize state

// create any functions we need for modifying the state

// return whatever we want another component to have access to (count, incremen

const [count, setCount] = useState(0)

function increment(){

setCount(prevCount => prevCount + 1)

return {count, increment}

// equivalent to return {count: count, increment: increment}

export default useCounter


```

The difference in exporting an object and not an array like useState is that we can controll the flexibility
in naming.

With an array user can choose any names for the values, but with an object the user of that hook needs
to use our names.

```jsx

// App.js

import React, {useState} from "react"

import useCounter from "./useCounter"

function App() {

const [number, add] = useCounter()

return (

<div>

<h1>The count is {number}</h1>

<button onClick={add}>Add 1</button>

</div>

export default App

```

### Custom Hooks Practice - refactor Toggler

Code or previous Toggler

```jsx
import React, {Component} from "react"

class Toggler extends Component {

state = {

on: this.props.defaultOnValue

static defaultProps = {

defaultOnValue: false

toggle = () => {

this.setState(prevState => ({on: !prevState.on}))

render() {

return (

<div>

{this.props.render({

on: this.state.on,

toggle: this.toggle

})}

</div>

export default Toggler

```
Now Favorite.js that uses Toggler gets pretty nested:

```jsx

import React, {Component} from "react"

import Toggler from "./Toggler"

function Favorite(props) {

return (

<Toggler render={

({on, toggle}) => (

<div>

<h3>Click heart to favorite</h3>

<h1>

<span

onClick={toggle}

>

{on ? " " : "♡"}

</span>

</h1>

</div>

}/>

export default Favorite

```

Create a Custom Hook:

```jsx
// useToggler.js

import {useState} from "react"

function useToggler(deafultOnValue = false) {

// Create the state

const [isToggledOn, setIsToggledOn] = useState(deafultOnValue)

// Create a function for easily flipping the isToggledOn value

function toggle() {

setIsToggledOn(prev => !prev)

// Return something useful for whatever component will be using this hook

return [isToggledOn, toggle]

export default useToggler

```

Change in Favorite.js

```jsx

import React, {Component} from "react"

import useToggler from "./useToggler"

function Favorite(props) {

const [isFavorited, toggle] = useToggler(false)

return (

<div>

<h3>Click heart to favorite</h3>


<h1>

<span

onClick={toggle}

>

{isFavorited ? " " : "♡"}

</span>

</h1>

</div>

export default Favorite

```

Note that for specifing a default value you cann use normal JS default values

So if there is something you wan't to reuse accorss your app you can use Custom Hooks.

---

### Speed Typing Game Part 8

Moving Business Logic to a custom hook

We create a folder called hooks and inside:

(As we are going to return a lot of things in this case we will return an object):

In this example we offload business logic from a component to another hook. And it can be good for
separation of concerns

```jsx
// useWordGame.js

import {useState, useEffect, useRef} from "react"

function useWordGame(startingTime = 10) {

const [text, setText] = useState("")

const [timeRemaining, setTimeRemaining] = useState(startingTime)

const [isTimeRunning, setIsTimeRunning] = useState(false)

const [wordCount, setWordCount] = useState(0)

const textBoxRef = useRef(null)

function handleChange(e) {

const {value} = e.target

setText(value)

function calculateWordCount(text) {

const wordsArr = text.trim().split(" ")

return wordsArr.filter(word => word !== "").length

function startGame() {

setIsTimeRunning(true)

setTimeRemaining(startingTime)

setText("")

textBoxRef.current.disabled = false

textBoxRef.current.focus()

function endGame() {
setIsTimeRunning(false)

setWordCount(calculateWordCount(text))

useEffect(() => {

if(isTimeRunning && timeRemaining > 0) {

setTimeout(() => {

setTimeRemaining(time => time - 1)

}, 1000)

} else if(timeRemaining === 0) {

endGame()

}, [timeRemaining, isTimeRunning])

return {textBoxRef, handleChange, text, isTimeRunning, timeRemaining, startGame, wordCount}

export default useWordGame

```

```jsx

// App.js

import React, {useState, useEffect, useRef} from "react"

import useWordGame from "./hooks/useWordGame"

function App() {

const {

textBoxRef,

handleChange,
text,

isTimeRunning,

timeRemaining,

startGame,

wordCount

} = useWordGame(5)

return (

<div>

<h1>How fast do you type?</h1>

<textarea

ref={textBoxRef}

onChange={handleChange}

value={text}

disabled={!isTimeRunning}

/>

<h4>Time remaining: {timeRemaining}</h4>

<button

onClick={startGame}

disabled={isTimeRunning}

>

Start

</button>

<h1>Word count: {wordCount}</h1>

</div>

```

You might also like