Table of Contents
1. useState()
useState()
has two parameters: the first is the value of the state, and the second is the function that manages the state.
import React, { useState } from "react"
const App = () => {
const [authForm, setAuthForm] = useState({
username: "",
password: "",
})
const handleChange = event => {
const { name, value } = event.target
setAuthForm(prevState => ({
...prevState,
[name]: value,
}))
}
return (
<>
<input
name="username"
value={authForm.username}
onChange={handleChange}
/>
<input
name="password"
value={authForm.password}
onChange={handleChange}
/>
</>
)
}
export default App
1.1 Input Form Hooks Demo
For example, the form authForm
above can be encapsulated into a custom form logic hook specifically to handle form inputs.
useFrom.js
import { useState } from "react"
const useForm = initState => {
const [form, setForm] = useState(initState)
return [
form,
event => {
setForm({
...form,
[event.target.name]: event.target.value,
})
},
]
}
export default useForm
App.js
Since we return an array in useForm
, the naming doesn't need to match the one in useForm
. We access the corresponding parameters using the index. (Index 0 is the state, and index 1 is the function that manages the state.)
import React, { useState } from "react"
import { useForm } from "./useForm"
export const App = () => {
const [authForm, setAuthForm] = useForm({
username: "",
email: "",
password: "",
})
return (
<>
<input name="username" value={authForm.username} onChange={setAuthForm} />
<input name="password" value={authForm.password} onChange={setAuthForm} />
<input name="email" value={authForm.email} onChange={setAuthForm} />
</>
)
}
1.2 Counter Demo
useCounter.jsx
import React, { useState } from "react"
const useCounter = initState => {
const [count, setCount] = useState(initState)
const increment = (payload = 0) => {
setCount(prevCnt => prevCnt + payload)
}
return [count, increment]
}
export default useCounter
App.jsx
import React, { useState } from "react"
import useCounter from "./useCounter"
const App = () => {
const [count, setCount] = useCounter(10)
return (
<div className="app-container">
<p>{count}</p>
<button onClick={setCount}>Increment</button>
</div>
)
}
export default App
2. useEffect()
Previously, in class components, we could manage the state lifecycle using componentDidMount
and other functions. Now, we can use useEffect
to manage component rendering or handle third-party API request data.
useEffect()
has two parameters: the first is the callback function, which defines the operation to be executed. The second parameter is the dependencies for the effect. When any of the dependencies change, the useEffect
will be triggered.
Effect Dependencies []
can have 0 or multiple parameters.
- 0 parameters
[]
is similar tocomponentDidMount
, meaning it triggers when the component first renders. - Multiple parameters will trigger the effect whenever any of the dependencies are updated.
useEffect(() => {
//action
}, [dependencies])
2.1 API Data Fetching
If it's a POST
request or if you need to call fetchSubject
later, the second parameter can also include those dependencies.
useSubjectApi.js
import { useState, useEffect } from "react"
const useSubjectApi = subject_id => {
const [subject, setSubject] = useState()
const [loading, setLoading] = useState(true)
const [error, setError] = useState(false)
useEffect(() => {
const fetchSubject = async () => {
try {
const response = await fetch(
`https://api.bgm.tv/subject/${subject_id}?responseGroup=large`
)
const data = await response.json()
setSubject(data)
} catch (err) {
setError(true)
}
setLoading(false)
}
fetchSubject()
}, [URL])
const res = {
subject,
loading,
error,
}
return [res]
}
export default useSubjectApi
App.js
import React, { useState, useEffect } from "react"
import useSubjectApi from "./Hooks/useSubjectApi"
const App = () => {
const [data] = useSubjectApi(51)
if (data.error || data.loading) {
return <p>Loading...</p>
}
const subject = data.subject
return (
<>
<h1>{subject.name}</h1>
<img src={subject.images.large} style={{ width: 150 }} />
</>
)
}
export default App
3. useContext()
- Create the relevant state, naming it something like
UserContext
, and initialize the state, or set it tonull
. - Use
Provider
at the parent level to provide the data where needed. - In the child components that need the state, use
useContext
to act as aConsumer
and receive the data.
UserContext.js
import { createContext } from "react"
export const UserContext = createContext(null)
Using the previously created UserContext
as the provider (Provider), all child components can use useContext
to access the state provided by the Provider.
App.js
import React, { useState, useEffect } from "react"
import { UserContext } from "./Context/UserContext"
import Dashboard from "./Components/Dashboard"
import ProfileMenu from "./Components/ProfileMenu"
const App = () => {
return (
<UserContext.Provider
value={{
userName: "yang_tk",
status: "online",
}}
>
<>
<ProfileMenu />
<Dashboard />
</>
</UserContext.Provider>
)
}
export default App
Then, we can reference the state of our UserNameContext
in both ProfileMenu
and Dashboard
components.
ProfileMenu.js
import React, { useContext } from "react"
import { UserContext } from "../Context/UserContext"
const ProfileMenu = () => {
const user = useContext(UserContext)
return (
<>
<h1>This is profile menu</h1>
<p>{user.userName}</p>
<p>{user.status}</p>
</>
)
}
export default ProfileMenu
Dashboard.js
import React, { useContext } from "react"
import { UserContext } from "../Context/UserContext"
const Dashboard = () => {
const { userName } = useContext(UserContext)
return (
<>
<h1>This is dashboard</h1>
<p>Welcome back {userName}</p>
</>
)
}
export default Dashboard
4. useReducer(): 状态管理
Let's first look at the parameters of useReducer()
:
const [state, dispatch] = useReducer(reducer, initialState)
- state is the current state value of the function.
- dispatch is used to dispatch actions to trigger state changes.
- reducer is the function that defines how the state changes based on the dispatched actions.
- initialState is the initial value of the state.
counterReducer.js
const counterReducer = (state, action) => {
switch (action.type) {
case "INCREMENT":
return {
...state,
count: state.count + 1,
}
case "DECREMENT":
return {
...state,
count: state.count - 1,
}
case "RESET":
return {
...state,
count: 0,
}
default:
return state
}
}
export default counterReducer
App.js
import { counterReducer } from "./reducers/counterReducer"
const App = () => {
const initState = {
count: 0,
}
const [state, dispatch] = useReducer(counterReducer, initState)
return (
<>
<button onClick={() => dispatch({ type: "increment" })}>Increment</button>
<button onClick={() => dispatch({ type: "decrement" })}>Decrement</button>
<button onClick={() => dispatch({ type: "reset" })}>Reset</button>
<p>{state.count}</p>
</>
)
}
export default App