This series will cover the use of React Hooks, starting with useState, and will include the following:
- useState
- useEffect
- useContext
- useReducer
- useCallback
- useMemo
- useRef
- custom hooks
Learn the React Hooks API to help you use React in your work. This series uses a lot of sample code and effect demonstrations, making it easy for beginners and refreshers to use.
Having learned so much about the official hooks API so far, we can create hooks of our own, and even developers are encouraged to abstract component logic into custom hooks for easy reuse.
A custom Hook is a function whose name starts with “use” that can call other hooks from within.
With custom hooks, component logic can be extracted into reusable functions.
UseDocumentTitle sample
Function = function
We want to create a counter, and when the value of the counter changes, we want to change the Title of the page
DocTitleOne.tsx
import React, { useState, useEffect } from 'react'
function DocTitleOne() {
const [count, setCount] = useState(0)
useEffect(() = > {
document.title = `Count - ${count}`
}, [count])
return (
<div>
<button
onClick={()= > {
setCount(count + 1)
}}
>Count - {count}</button>
</div>)}export default DocTitleOne
Copy the code
App.tsx
import React from 'react'
import './App.css'
import DocTitleOne from './components/31DocTitleOne'
const App = () = > {
return (
<div className="App">
<DocTitleOne />
</div>)}export default App
Copy the code
The page display is as follows
It worked fine, and then there was another incremental requirement that the page should be able to change the Title of the page in another component, so we created a new component.
DocTitleTwo.tsx
import React, { useState, useEffect } from 'react'
function DocTitleTwo() {
const [count, setCount] = useState(0)
useEffect(() = > {
document.title = `Count - ${count}`
}, [count])
return (
<div>
<button
onClick={()= > {
setCount(count + 1)
}}
>Count - {count}</button>
</div>)}export default DocTitleTwo
Copy the code
App.tsx
import React from 'react'
import './App.css'
import DocTitleOne from './components/31DocTitleOne'
import DocTitleTwo from './components/31DocTitleTwo'
const App = () = > {
return (
<div className="App">
<DocTitleOne />
<DocTitleTwo />
</div>)}export default App
Copy the code
The page display is as follows
Reviewing the code, DocTitleTwo clearly duplicates DocTitleOne’s code, which you don’t want to repeat if you have 10 components that change the page title. This is where custom hooks are needed.
In this example, we can create a custom Hook to set the title of the page. Then use this custom Hook in different components.
Abstract useDocumentTitle hook
useDocumentTitle.tsx
import { useEffect } from 'react'
function useDocumentTitle(count: number) {
useEffect(() = > {
document.title = `Count - ${count}`
}, [count])
}
export default useDocumentTitle
Copy the code
DocTitleOne.tsx
import React, { useState } from 'react'
import useDocumentTitle from './hooks/useDocumentTitle'
function DocTitleOne() {
const [count, setCount] = useState(0)
useDocumentTitle(count)
return (
<div>
<button
onClick={()= > {
setCount(count + 1)
}}
>Count - {count}</button>
</div>)}export default DocTitleOne
Copy the code
DocTitleTwo.tsx
import React, { useState } from 'react'
import useDocumentTitle from './hooks/useDocumentTitle'
function DocTitleTwo() {
const [count, setCount] = useState(0)
useDocumentTitle(count)
return (
<div>
<button
onClick={()= > {
setCount(count + 1)
}}
>Count - {count}</button>
</div>)}export default DocTitleTwo
Copy the code
App.tsx
import React from 'react'
import './App.css'
import DocTitleOne from './components/31DocTitleOne'
import DocTitleTwo from './components/31DocTitleTwo'
const App = () = > {
return (
<div className="App">
<DocTitleOne />
<DocTitleTwo />
</div>)}export default App
Copy the code
The page display is as follows
Let’s review the code
In DocTitleOne, we introduce the useDocumentTitle we defined, passing in the count state. UseDocumentTitle executes the code, sets the page title initial value to 0, and continues rendering the DocTitleOne JSX section. When the button is clicked, count changes to 1, triggering Rerender of DocTitleOne, useDocumentTitle changes to 1, and the page title changes to 1.
UseCounter sample
Redundant writing
CounterOne.tsx
import React, {useState} from 'react'
function CounterOne() {
const [count, setCount] = useState(0)
const increment = () = > {
setCount(prevCount= > prevCount + 1)}const decrement = () = > {
setCount(prevCount= > prevCount - 1)}const reset = () = > {
setCount(0)}return (
<div>
<h2>Count - {count}</h2>
<button onClick={increment}>increment</button>
<button onClick={decrement}>decrement</button>
<button onClick={reset}>reset</button>
</div>)}export default CounterOne
Copy the code
CounterTwo.tsx
import React, {useState} from 'react'
function CounterTwo() {
const [count, setCount] = useState(0)
const increment = () = > {
setCount(prevCount= > prevCount + 1)}const decrement = () = > {
setCount(prevCount= > prevCount - 1)}const reset = () = > {
setCount(0)}return (
<div>
<h2>Count - {count}</h2>
<button onClick={increment}>increment</button>
<button onClick={decrement}>decrement</button>
<button onClick={reset}>reset</button>
</div>)}export default CounterTwo
Copy the code
App.tsx
import React from 'react'
import './App.css'
import CounterOne from './components/32CounterOne'
import CounterTwo from './components/32CounterTwo'
const App = () = > {
return (
<div className="App">
<CounterOne />
<CounterTwo />
</div>)}export default App
Copy the code
The page display is as follows
We have a lot of duplicate code for the same problem, so let’s see how to optimize it using custom hooks.
UseCounter abstract
useCounter.tsx
import { useState } from 'react'
function useCounter() {
const [count, setCount] = useState(0)
const increment = () = > {
setCount(prevCount= > prevCount + 1)}const decrement = () = > {
setCount(prevCount= > prevCount - 1)}const reset = () = > {
setCount(0)}return [count, increment, decrement, reset]
}
export default useCounter
Copy the code
CounterOne.tsx
import React from 'react'
import useCounter from './hooks/useCounter'
function CounterOne() {
const [count, increment, decrement, reset] = useCounter()
return (
<div>
<h2>Count - {count}</h2>
<button onClick={increment}>increment</button>
<button onClick={decrement}>decrement</button>
<button onClick={reset}>reset</button>
</div>)}export default CounterOne
Copy the code
CounterTwo.tsx
import React from 'react'
import useCounter from './hooks/useCounter'
function CounterTwo() {
const [count, increment, decrement, reset] = useCounter()
return (
<div>
<h2>Count - {count}</h2>
<button onClick={increment}>increment</button>
<button onClick={decrement}>decrement</button>
<button onClick={reset}>reset</button>
</div>)}export default CounterTwo
Copy the code
App.tsx
import React from 'react'
import './App.css'
import CounterOne from './components/32CounterOne'
import CounterTwo from './components/32CounterTwo'
const App = () = > {
return (
<div className="App">
<CounterOne />
<CounterTwo />
</div>)}export default App
Copy the code
The page display is still as follows
As you can see, our code structure is better now. We can also set the initial value for counter in useCounter, as follows
useCounter.tsx
import { useState } from 'react'
function useCounter(initialValue = 0) {
const [count, setCount] = useState(initialValue)
const increment = () = > {
setCount(prevCount= > prevCount + 1)}const decrement = () = > {
setCount(prevCount= > prevCount - 1)}const reset = () = > {
setCount(initialValue)
}
return [count, increment, decrement, reset]
}
export default useCounter
Copy the code
When used, the corresponding initial value can be passed
const [count, increment, decrement, reset] = useCounter(10)
Copy the code
We can also modify each increment or subtraction as follows
import { useState } from 'react'
function useCounter(initialValue = 0, value = 1) {
const [count, setCount] = useState(initialValue)
const increment = () = > {
setCount(prevCount= > prevCount + value)
}
const decrement = () = > {
setCount(prevCount= > prevCount - value)
}
const reset = () = > {
setCount(initialValue)
}
return [count, increment, decrement, reset]
}
export default useCounter
Copy the code
When used, the corresponding input parameter can also be added
const [count, increment, decrement, reset] = useCounter(10.5)
Copy the code
UseInput sample
The example is a simple form in which the user can fill in a name
Function = function
UserForm.tsx
import React, { useState, FormEvent } from 'react'
function UserForm() {
const [firstName, setFirstName] = useState(' ')
const [lastName, setLastName] = useState(' ')
const submitHandler = (e: FormEvent) = > {
e.preventDefault()
console.log(`Hello ${firstName} ${lastName}`)}return (
<div>
<form onSubmit={submitHandler}>
<div>
<label htmlFor="">First name</label>
<input
type="text"
value={firstName}
onChange={(e)= > {
setFirstName(e.target.value)
}}
/>
</div>
<div>
<label htmlFor="">Last name</label>
<input
type="text"
value={lastName}
onChange={(e)= > {
setLastName(e.target.value)
}}
/>
</div>
<button>submit</button>
</form>
</div>)}export default UserForm
Copy the code
App.tsx
import React from 'react'
import './App.css'
import UserForm from './components/33UserForm'
const App = () = > {
return (
<div className="App">
<UserForm />
</div>)}export default App
Copy the code
Abstract useInput hook
useInput.tsx
import { useState } from 'react'
function useInput(initialValue: string) {
const [value, setValue] = useState(initialValue)
const reset = () = > {
setValue(initialValue)
}
const bind = {
value,
onChange(e: any) {
setValue(e.target.value)
}
}
return [value, bind, reset]
}
export default useInput
Copy the code
UserForm.tsx
import React, { FormEvent } from 'react'
import useInput from './hooks/useInput'
function UserForm() {
const [firstName, bindFirstName, resetFirstName] = useInput(' ')
const [lastName, bindLastName, resetLastName] = useInput(' ')
const submitHandler = (e: FormEvent) = > {
e.preventDefault()
console.log(`Hello ${firstName} ${lastName}`)
// @ts-ignore
resetFirstName()
// @ts-ignore
resetLastName()
}
return (
<div>
<form onSubmit={submitHandler}>
<div>
<label htmlFor="">First name</label>
<input
type="text"
{. bindFirstName} / >
</div>
<div>
<label htmlFor="">Last name</label>
<input
type="text"
{. bindLastName} / >
</div>
<button>submit</button>
</form>
</div>)}export default UserForm
Copy the code
The page display
summary
This chapter focuses on custom hooks, with three examples to help us learn abstract and reuse code. There are also many people in the community who have written their own custom hooks that you can go and learn. You are also encouraged to create your own custom hooks.
This concludes the series. Good luck. We’ll all learn something.