Miguel Silva - React Curse Part1 in Markdown
Miguel Silva - React Curse Part1 in Markdown
## Table of Contents
* [Introduction](#introduction)
* [React.Fragment](#react.fragment)
* [Default Props](#default-props)
* [Prop Types](#prop-types)
* [Re-Usability](#re-usability)
* [React Children](#react-children)
* [First HOC](#first-high-order-component)
* [Toogle HOC](#toogle-hoc)
* [Render Props](#render-props)
---
## Introduction
* Introduction to React
* Props
* State
* Forms
* Conditional Rendering
* Reusability / Patterns
* Performance / Optimization
* Context
* Hooks
* React Router
* Capstone Project
* Redux
```jsx
function App(){
```
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
}
})
```
```jsx
```
```jsx
state = {
count: 0,
age: 3
```
* Desconstructuring properties:
```jsx
```
```jsx
---
### 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>
```
```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.
```jsx
```
```jsx
<>
<Comp1/>
<Comp2/>
</>
```
---
function Card(props){
const styles ={
backgroundColor: props.cardColor,
height: 100,
width: 100
return(
<div style={styles}></div>
Card.defaultProps = {
cardColor: "blue"
```
So if you create a Card without passing cardColor property it will use blue
```jsx
```
---
```jsx
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
```
```jsx
import React from "react"
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>
```
---
[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
```powershell
```
```jsx
function Card(props){
Card.propTypes = {
cardColor: PropTypes.string
```
```jsx
```
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
```
***Note**If you set a prop as required but you have a defaultProp, you won't get a warning.
**Enum example**
```jsx
```
```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
* Inheritance: OOP
> they always prefer composition instead inheritance to reuse code between componenets
1. Components w/props
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.
---
```jsx
```
```jsx
// CTS.js
function CTA() {
return (
<div className="border">
</div>
```
```css
/* styles in index.html */
.border {
border-radius: 5px;
}
```
```jsx
// App.js
function App() {
return (
<div>
<CTA />
</div>
```
```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`
```jsx
// App.js
import React from "react"
function App() {
return (
<div>
<CTA>
</CTA>
</div>
```
```jsx
// CTS.js
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
function App() {
return (
<div>
<CTA>
</CTA>
<CTA>
<form>
<br />
<button>Submit</button>
</form>
</CTA>
</div>
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.
```jsx
<CTA someProp="value">
</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
---
* 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.
```
Example:
```jsx
```
or
```jsx
```
---
It's a good practice create a folder HOCs with those elements inside.
```jsx
// withExtraPropAdded.js
import React form 'react'
return function(props){
return(
```
```jsx
// App.js
function App(props) {
console.log(props.anotherProp)
return (
<div>Hello world!</div>
Or at the end:
```jsx
```
```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**
```jsx
```
```jsx
```
```jsx
export default function withExtraPropAdded(){
```
```jsx
```
---
As said before HOC's are used to improve or give new habilities to the components.
1. Menu
2. Favorite
Both implement a toggle functionality that hide/shows some elements by updating a flag in state:
```jsx
// menu.js
state = {
show: true
toggleShow = () => {
this.setState(prevState => {
return {
show: !prevState.show
})
render() {
return (
<div>
<h6>Signed in as Coder123</h6>
<a>Your Profile</a>
<a>Your Repositories</a>
<a>Your Stars</a>
<a>Your Gists</a>
</nav>
</div>
```
```jsx
// favorite.js
state = {
isFavorited: false
toggleFavorite = () => {
this.setState(prevState => {
return {
isFavorited: !prevState.isFavorited
})
render() {
return (
<div>
<h1>
<span
onClick={this.toggleFavorite}
>
</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
state = {
on: this.props.defaultOnValue
toggle = () => {
this.setState(prevState => {
return {
on: !prevState.on
})
render() {
return (
}
export function withToggler(component, optionsObj) {
return function(props) {
return (
```
**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
render() {
return (
<div>
<h1>
<span
onClick={this.props.toggle}
>
{this.props.on ? " " : "♡"}
</span>
</h1>
</div>
```
```jsx
// menu.js
render() {
return (
<div>
<h6>Signed in as Coder123</h6>
<a>Your Profile</a>
<a>Your Repositories</a>
<a>Your Stars</a>
<a>Your Gists</a>
</nav>
</div>
```
*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
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
function Example(props) {
return (
<div>
{props.render(true)}
</div>
```
```jsx
function App() {
return (
<div>
<Example render={
function(isDaytime) {
return (
}/>
</div>
```
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).
They both are JS function. But the difference is that a functional component needs to return some JSX
___
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
state = {
on: this.props.defaultOnValue
static defaultProps = {
defaultOnValue: false
}
toggle = () => {
render() {
return (
<div>
{this.props.render({
on: this.state.on,
toggle: this.toggle
})}
</div>
```
```jsx
// Favorite.js
function Favorite(props) {
return (
<Toggler render={
<div>
<span
onClick={toggle}
>
</span>
</h1>
</div>
}/>
```
```jsx
// Menu.js
// 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>
<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>
)}/>
```
It's a good practice that you pass a single object in the render function instead of multiple parameters
```jsx
// App.js
function App() {
return (
<div>
return (
)
}}/>
<hr />
<Favorite />
</div>
```
```jsx
// Menu.js
// 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>
<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>
)
}
```
```jsx
// App.js
function App() {
return (
<div>
<Toggler defaultOnValue={true}>
return (
)}}
</Toggler>
<hr />
<Favorite />
</div>
```
```jsx
// Toogler.js
state = {
on: this.props.defaultOnValue
static defaultProps = {
defaultOnValue: false
toggle = () => {
render() {
return (
<div>
{this.props.children({
on: this.state.on,
toggle: this.toggle
})}
</div>
}
export default Toggler
```
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
state = {
loading: false,
data: null,
error: null
componentDidMount() {
this.setState({loading: true})
fetch(this.props.url)
render() {
```
```jsx
// App.js
function App() {
return (
<div>
<DataFetcher url="https://swapi.dev/api/people/1/">
loading ?
<h1>Loading...</h1> :
)}
</DataFetcher>
</div>
```
----
* 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
If state of App changes all the tree will be re-rendered. This is a decrease in performance
## Performance
```jsx
```
* for objects it will return false if they are not the same reference:
```jsx
```
**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
```
But if we have:
```jsx
const state = {
favNumber: 42,
name: "Bob",
address: {
zip: 12345
const state2 = {
favNumber: 42,
name: "Bob",
address: {
zip: 12345
```
```jsx
const person = {
name: "Sarah"
```
#### In arrays
```jsx
const arr1 = [1, 2, 3]
```
both arrays will be shallow equal because the === comparison between each index and value is the
same.
```jsx
```
---
### shouldCompoenntUpdate
* Receives the upcoming props and state so you can compare them against current props and state
* Don't do deep equality checks in here (recommendation by ReactJS) because it's going to be inefficient
Components:
* App
* GrandParent
* Parent
* Child
* Grand Child
```
>[ ] [ ] [ ] [ ] 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
shouldComponentUpdate(nextProps, nextState) {
return false
return true
render() {
console.log("[ ] [ ] [ ] [ ] rendered")
return (
<div>
<Parent />
<Parent />
</div>
```
initial render will render everything. But when we change state in App it won't re render GrandParent
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
* Alternative to React.Component
* Skips rendering all children in the tree automatically, so they must be "pure" as well
So in GrandParent:
```jsx
// GrandParent.js
render() {
console.log("[ ] [ ] [ ] [ ] rendered")
return (
<div>
<Parent />
<Parent />
</div>
```
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 />
```
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
* 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
function GrandParent(props) {
console.log("[ ] [ ] [ ] [ ] rendered")
return (
<div>
<Parent />
<Parent />
</div>
```
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.
```jsx
console.log("[ ] [ ] [ ] [ ] rendered")
return (
<div>
<Child />
<Child />
</div>
})
```
#### areEqual
```jsx
function areEual(prevProps, nextProps){
```
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
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.
Context
: provides a way to pass data thourhg the coponent tree without having to pass props down manually at
every level
Usually you pass data and a method to modify that data (and the provider will update that data to the
other consumers)
### Implementation
```jsx
// ThemeContext.js
```
```jsx
// index.js
ReactDOM.render(
<ThemeContext.Provider value={"light"}>
<App />
</ThemeContext.Provider>,
document.getElementById("root")
```
```jsx
// Button.js
render() {
return (
Button.contextType = ThemeContext
```
```jsx
render() {
return (
<header className={`${theme}-theme`}>
</header>
```
contextType is limited , it only can be used in class and it doesn't allow to specify a method to change
the data.
---
#### Example2
```jsx
// userContext.js
import React from "react"
```
```jsx
// index.js
ReactDOM.render(
<UserContext.Provider value={"bobz123"}>
<App />
</UserContext.Provider>,
document.getElementById("root")
```
```jsx
// App.js
render() {
return (
<div>
<Header />
<main>
</main>
</div>
```
```jsx
// Header.js
render() {
return (
<header>
<p>Welcome, {username}!</p>
</header>
```
### Context.Consumer
```jsx
// Button.js
function Button(props) {
return (
<ThemeContext.Consumer>
{theme => (
)}
</ThemeContext.Consumer>
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.
```jsx
// Button.js
function Button(props) {
return (
Button.propTypes = {
Button.defaultProps = {
theme: "light"
}
```
```jsx
function App() {
return (
<div>
<Header />
<ThemeContext.Consumer>
{theme => (
)}
</ThemeContext.Consumer>
</div>
```
In this way you can choose which buttons are going to use the context and which not.
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
render() {
return (
<Provider value={"light"}>
{this.props.children}
</Provider>
```
```jsx
// index.js
ReactDOM.render(
<ThemeContextProvider value={"light"}>
<App />
</ThemeContextProvider>,
document.getElementById("root")
```
```jsx
// Header.js
function Header(props) {
return (
<ThemeContextConsumer>
{theme => (
<header className={`${theme}-theme`}>
</header>
)}
</ThemeContextConsumer>
Benefits:
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:
```jsx
state = {
theme: "light"
toggleTheme = () => {
this.setState(prevState => {
return {
})
render() {
return (
</Provider>
```
```jsx
// Button.js
function Button(props) {
return (
<ThemeContextConsumer>
{context => (
)}
</ThemeContextConsumer>
```
So clicking the button all the consumers that take the theme value will be updated
### Chanllege: Context Practice 3
Controlled Components (use forms) for now need to be written in class components
```jsx
// Usercontext.js
state = {
username: "bob123"
this.setState({username})
render() {
return (
{this.props.children}
</Provider>
}
export {UserContextProvider, Consumer as UserContextConsumer}
```
```jsx
// index.js
ReactDOM.render(
<UserContextProvider>
<App />
</UserContextProvider>,
document.getElementById("root")
```
```jsx
// Header.js
function Header() {
return (
<header>
<UserContextConsumer>
{({username}) => (
<p>Welcome, {username}!</p>
)}
</UserContextConsumer>
</header>
```
```jsx
// App.js
state = {
newUsername: ""
this.setState({[name]: value})
render() {
return (
<div>
<Header />
<UserContextConsumer>
<main>
<input
type="text"
name="newUsername"
placeholder="New username"
value={this.state.newUsername}
onChange={this.handleChange}
/>
</main>
)}
</UserContextConsumer>
</div>
```
Caveats:
* 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)
* 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
---
## React Hooks
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.
There are still 2 life cycle methods that are not available in hooks:
* getSnapshotBeforeUpdate()
* componentDidCatch()
* useState
* useEffect
* useContext
* useRef
* useReducer
* useMemo
* useCallback
* useImperativeHandle
* useLayoutEeffect
* useDebugValue
You need to be aware because using useMemo and useCallback for improving performance sometimes
can be good.
### useState
```jsx
function App(){
function increment(){
return(
<div>
<h1>{count}</h1>
<button onClick={increment}>Increment</button>
</div>
```
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.
```jsx
setState(prevState => {
count: 0,
```
```jsx
```
---
### 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
function App() {
function handleChange(event) {
function handleSubmit(event) {
event.preventDefault()
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}
</>
```
---
### useEffect
* componentDidMount
* componentDidUpdate
* componentWillUnmount
Example of uses:
* Network request
```jsx
function App() {
function increment() {
function decrement() {
useEffect(() => {
setColor(randomcolor())
}, [count])
return (
<div>
<button onClick={decrement}>Decrement</button>
</div>
```
Simulating componentDidMount:
```jsx
useEffect(() => {
setColor(randomcolor())
}, [])
```
Simulating `componentWillUnmount`:
```jsx
useEffect(() => {
}, 1000)
// clean up function
}, [])
useEffect(() => {
setColor(randomcolor())
}, [count])
```
So ReactJS run useEffect and stores the function that receives. And when the component get's
unmounted ReactJS run that function.
---
Game countdown:
```jsx
useEffect(() => {
setTimeout(() => {
}, 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
* After the game ends, make it so the user can click the Start button again
*/
function App() {
const STARTING_TIME = 5
function handleChange(e) {
setText(value)
function calculateWordCount(text) {
}
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(() => {
setTimeout(() => {
}, 1000)
endGame()
}, [timeRemaining, isTimeRunning])
return (
<div>
<textarea
onChange={handleChange}
value={text}
disabled={!isTimeRunning}
/>
<button
onClick={startGame}
disabled={isTimeRunning}
>
Start
</button>
</div>
```
---
### useReef
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
// ...
```
Example:
Allowing that every time I press enter the focus return to input:
```jsx
function App() {
function handleChange(event) {
setNewTodoValue(event.target.value)
function addTodo(event) {
event.preventDefault()
setNewTodoValue("")
inputRef.current.focus()
return (
<div>
<form>
</form>
{allTodos}
</div>
```
==Important==
```jsx
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
/**
* Challenge:
* Make the input box focus (DOM elements have a method called .focus())
*/
function App() {
const STARTING_TIME = 5
function handleChange(e) {
setText(value)
function calculateWordCount(text) {
}
function startGame() {
setIsTimeRunning(true)
setTimeRemaining(STARTING_TIME)
setText("")
textBoxRef.current.disabled = false
textBoxRef.current.focus()
function endGame() {
setIsTimeRunning(false)
setWordCount(calculateWordCount(text))
useEffect(() => {
setTimeout(() => {
}, 1000)
endGame()
}, [timeRemaining, isTimeRunning])
return (
<div>
<textarea
ref={textBoxRef}
onChange={handleChange}
value={text}
disabled={!isTimeRunning}
/>
<button
onClick={startGame}
disabled={isTimeRunning}
>
Start
</button>
</div>
```
---
### useContext
```jsx
```
exporting consumer won't be necessary
```jsx
// themeContext.js
state = {
theme: "dark"
toggleTheme = () => {
this.setState(prevState => {
return {
})
render() {
return (
{this.props.children}
</ThemeContext.Provider>
}
export {ThemeContextProvider, ThemeContext}
```
```jsx
// index.js
ReactDOM.render(
<ThemeContextProvider>
<App />
</ThemeContextProvider>,
document.getElementById("root")
```
```jsx
// App.js
function App() {
return (
<div>
<Header />
<Button />
</div>
```
```jsx
// Button.js
function Button(props) {
return (
<button
onClick={context.toggleTheme}
className={`${context.theme}-theme`}
>
Switch Theme
</button>
```
```jsx
// Header.js
function Header(props) {
return (
<header className={`${theme}-theme`}>
</header>
```
---
Before:
```jsx
// themeContext.js
state = {
theme: "dark"
}
toggleTheme = () => {
this.setState(prevState => {
return {
})
render() {
return (
{this.props.children}
</ThemeContext.Provider>
```
After:
```jsx
function ThemeContextProvider(props) {
return (
{props.children}
</ThemeContext.Provider>
```
---
Before:
```jsx
state = {
count: 0
increment = () => {
render() {
return (
<div>
</div>
```
After:
```jsx
function App(props){
function increment(){
return (
<div>
</div>
)
}
```
* HOC's
* Render Props
```jsx
function App() {
function increment() {
return (
<div>
</div>
)
}
```
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.
```jsx
// useCounter.js
function useCounter(){
// initialize state
function increment(){
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
function App() {
return (
<div>
</div>
```
```jsx
import React, {Component} from "react"
state = {
on: this.props.defaultOnValue
static defaultProps = {
defaultOnValue: false
toggle = () => {
render() {
return (
<div>
{this.props.render({
on: this.state.on,
toggle: this.toggle
})}
</div>
```
Now Favorite.js that uses Toggler gets pretty nested:
```jsx
function Favorite(props) {
return (
<Toggler render={
<div>
<h1>
<span
onClick={toggle}
>
</span>
</h1>
</div>
}/>
```
```jsx
// useToggler.js
function toggle() {
// Return something useful for whatever component will be using this hook
```
Change in Favorite.js
```jsx
function Favorite(props) {
return (
<div>
<span
onClick={toggle}
>
</span>
</h1>
</div>
```
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.
---
(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
function handleChange(e) {
setText(value)
function calculateWordCount(text) {
function startGame() {
setIsTimeRunning(true)
setTimeRemaining(startingTime)
setText("")
textBoxRef.current.disabled = false
textBoxRef.current.focus()
function endGame() {
setIsTimeRunning(false)
setWordCount(calculateWordCount(text))
useEffect(() => {
setTimeout(() => {
}, 1000)
endGame()
}, [timeRemaining, isTimeRunning])
```
```jsx
// App.js
function App() {
const {
textBoxRef,
handleChange,
text,
isTimeRunning,
timeRemaining,
startGame,
wordCount
} = useWordGame(5)
return (
<div>
<textarea
ref={textBoxRef}
onChange={handleChange}
value={text}
disabled={!isTimeRunning}
/>
<button
onClick={startGame}
disabled={isTimeRunning}
>
Start
</button>
</div>
```