React如何使用Hooks

一、State

步骤

  1. 导入useState
1
import React, {useState} from "react"
  1. 声明State
1
let [value, setValue] = useState(0)

数组第一个参数为使用的值,第二个参数为设置值的函数。useState的参数为默认值。

  1. 使用值
1
2
3
<div>
<span>{value}</span>
</div>
  1. 设置值、
1
setValue(value + 1)

参数即为对值得变更操作

代码示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import React, { useState } from "react";

function App() {
let [value, setValue] = useState(0);
const add1 = () => {
setValue(value + 1);
};
return (
<div>
<span>{value}</span>
<button onClick={add1}>+1</button>
</div>
);
}
export default App;

二、useReducer

步骤

  1. 导入useReducer
1
import { useReducer } from "react"
  1. 创建初始值
1
2
3
const initial = {
n: 0
}
  1. 创建所有操作类型
1
2
3
4
5
6
7
8
9
const reducer = (state, action) => {
if (action.type === "add") {
return { n: state.n + action.number }
} else if (action.type === 'multi') {
return { n: state.n - action.number }
} else {
throw new Error("未知类型")
}
}
  1. 使用useReducer,获得读写操作
1
const [state, dispatch] = useReducer(action, initial)

1
<div>{state.n}</div>

1
dispath(type: "add", numer: 1 )

代码示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
import React from "react"
import { useReducer } from "react"

const initial = {
n: 0
}

const reducer = (state, action) => {
if (action.type === 'add') {
return { n: state.n + action.number }
} else if (action.type = "multi") {
return { n: state.n - action.number }
} else {
throw new Error("未知类型")
}
}

const DemoUseReducer = () => {
const [state, dispatch] = useReducer(reducer, initial)
const add = () => {
dispatch({ type: "add", number: 1 })
}
return (
<>
<div>{state.n}</div>
<button onClick={add}>+1</button>
<button onClick={() => dispatch({ type: "multi", number: 3 })}>-3</button>
</>
)
}

export default DemoUseReducer

三、useContext

步骤

  1. 导入createContext、useContext
1
import React, { useState, createContext, useContext } from "react"
  1. 创建Context
1
const Context = createContext(null)
  1. 设置作用域,传递你需要使用的数据
1
2
3
4
5
6
return (
<Context.Provider value={{n, setN}}>
<Father/>
<Son/>
</Context.Provider>
)
  1. 在作用域中的组件解构传递的数据

Father

1
const {n, setN} = useContext(Context)
  1. 使用解构出来的数据

Father

1
<button onClick={()=>setN(n=>n+1)}>+1</button>

代码示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
import React, { useState, createContext, useContext } from "react"

const Context = createContext(null)

const DemoUseContext = () => {
const [n, setN] = useState(0)
return (
<Context.Provider value={{ n, setN }}>
<Father />
<Son />
</Context.Provider>
)
}

const Father = () => {
const { n, setN } = useContext(Context)
return (
<>
<div>我是爸爸{n}</div>
<button onClick={() => setN(n => n + 1)}>爸爸按钮+1</button>
</>
)
}

const Son = () => {
const { n, setN } = useContext(Context)
return (
<>
<div>我是儿子{n}</div>
<button onClick={() => setN(n => n - 1)}>儿子按钮-1</button>
</>
)
}

export default DemoUseContext

四、useEffect和useLayoutEffect

步骤

  1. 导入
1
import { useEffect, useLayoutEffect } from "react"
  1. 每次都执行
1
useEffect(()=>{})
  1. 第一次渲染执行
1
useEffect(()=>{},[])
  1. 在某个值变化的时候执行
1
useEffect(()=>{},[n])
  1. 在页面渲染前执行
1
useLayoutEffect(()=>{})

代码示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
import React, {useState, useEffect, useLayoutEffect} from "react"

const DemoUseEffect = () => {
const [display, setDisplay] = useState(true)
const [n, setN] = useState(0)
useEffect(() => {
console.log("我每次都执行")
})
useEffect(() => {
console.log("我只在第一次执行")
return () => {
console.log("我只在销毁的时候执行")
}
}, [])
useEffect(() => {
console.log("我只在n变化执行")
}, [n])
useLayoutEffect(() => {
console.log("我是在页面渲染前就执行结束")
})
return (
<>
{display ? <div>{n}</div> : null}
<button onClick={() => setN(n => n + 5)}>+5</button>
<button onClick={() => {
setDisplay(display => !display)
}}>消灭n
</button>
</>
)
}

export default DemoUseEffect

五、memo&useMemo&useCallback

步骤

  1. 导入
1
import React, {useMemo, useState, memo, useEffect, useCallback} from "react"
  1. memo包住不需要重新渲染的组件函数
1
2
3
4
5
6
7
8
const Childer = memo((props) => {
console.log("我是孩子,我不想执行")
return (
<>
<div>我是孩子 {props.childer}</div>
</>
)
})
  1. useMemo包住防止因对象地址变化而导致的误渲染
1
2
3
4
const childClick = useMemo(() => {
return () => {
}
}, [childer])

代码示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
import React, {useMemo, useState, memo, useEffect, useCallback} from "react"

const DemoUseMemoAndUseCallback = () => {
const [n, setN] = useState(0)
const [childer, setChilder] = useState(0)
useEffect(() => {
console.log("我变化了")
}, [n])
// 使用useMemo阻止因为对象地址变化而重新执行
const childClick = useMemo(() => {
return () => {
}
}, [childer])
// 等同于useMemo,比useMemo简单
const childClick2 = useCallback(() => {
})
return (
<>
<div>{n}</div>
<Childer childer={childer} childClick={childClick} childClick2={childClick2}/>
<button onClick={() => setN(n => n + 10)}>+10</button>
</>
)
}

// 使用memo阻止子组件state没改变,因父组件属性改变而重新渲染
const Childer = memo((props) => {
console.log("我是孩子,我不想执行")
return (
<>
<div>我是孩子 {props.childer}</div>
</>
)
})

export default DemoUseMemoAndUseCallback

六、useRef

步骤

  1. 导入
1
import { useRef } from "react"
  1. 声明变量
1
const count = useRef(0)
  1. 使用/修改值
1
count.current += 1

代码示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import React, {useEffect, useRef, useState} from "react"

const DemoUseRef = () => {
const count = useRef(0)
const [n, setN] = useState(0)
useEffect(() => {
count.current += 1
console.log("第" + count.current + "执行")
})
return (
<>
<div>{n}</div>
<button onClick={() => setN(n => n + 1)}>n+1</button>
</>
)
}

export default DemoUseRef

七、useImperativeHandle

步骤

  1. 导入
1
import { useImperativeHandle } from "react"
  1. 在父组件创建ref
1
const buttonRef = useRef()
  1. 传递给子组件
1
<button ref={buttonRef}>按钮</button>
  1. 子组件接收并对ref进行修改后返还出去
1
2
3
4
5
useImperativeHandle(ref, ()=>{
return {
x: ()=>console.log(1)
}
})

代码示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
import React, {forwardRef, useRef, useEffect, useImperativeHandle} from "react"

const DemoImperativeHandle = () => {
const buttonRef = useRef()
useEffect(() => {
console.log(buttonRef)
})
return (<>
<Son ref={buttonRef} onClick={() => console.log(buttonRef.current.x())}>按钮</Son>
</>)
}

const Son = forwardRef((props, ref) => {
const realRef = useRef()
useImperativeHandle(ref, () => {
return {
x: () => {
console.log(1)
},
ref: realRef
}
})
return (<>
<button ref={realRef} {...props}/>
</>)
})

export default DemoImperativeHandle

八、forwardRef

步骤

  1. 导入
1
import { forwardRef, useRef } from "react"
  1. 创建ref
1
const ref = useRef(null)
  1. 向组件传ref
1
<ChildNode ref={ref}>按钮</ChildNode>
  1. 使用forwardRef接收ref
1
2
3
4
5
6
7
8
const ChildNode = forwardRef((props, ref) => {
return (
<>
<button ref={ref} onClick={() => console.log(ref)}>{props.children}</button>
</>
)
})

代码示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
import React, {forwardRef, useRef} from "react"

const DemoForwardRef = () => {
const ref = useRef(null)
return (
<>
<div>我是本身的元素</div>
<ChildNode ref={ref}>按钮</ChildNode>
</>
)
}

const ChildNode = forwardRef((props, ref) => {
return (
<>
<button ref={ref} onClick={() => console.log(ref)}>{props.children}</button>
</>
)
})

export default DemoForwardRef

拓展一、useContext&useReducer代替Redux

步骤

  1. 创建Store数据仓库
1
cosnt store = {user: null, books: null, movies}
  1. 创建reducer行为操作列表
1
2
3
4
5
6
7
8
9
10
11
12
const reducer = (state, action) => {
switch (action.type) {
case "setUser":
return {...state, user: action.user}
case "setBooks":
return {...state, books: action.books}
case "setMovies":
return {...state, movies: action.movies}
default:
throw new Error("位置类型")
}
}
  1. 创建Context
1
const Context = createContext(null)
  1. 创建读写的API
1
const [state, dispatch] = useReducer(reducer, store)
  1. 定义作用域
1
2
3
4
5
<Context.Provider value={{state, dispatch}}>
<User/>
<Books/>
<Movies/>
</Context.Provider>
  1. 使用传递的数据
1
const {state, dispatch} = useContext(Context)
  1. 对数据进行操作

1
<div>{state.user.name}</div>

1
dispatch({type: "setUser", user: 数据})

代码示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
import React, {useContext, useEffect, useReducer, createContext} from "react"

// 数据仓库
const store = {
user: null,
books: null,
movies: null
}

// 行为类型
const reducer = (state, action) => {
switch (action.type) {
case "setUser":
return {...state, user: action.user}
case "setBooks":
return {...state, books: action.books}
case "setMovies":
return {...state, movies: action.movies}
default:
throw new Error("位置类型")
}
}

// 创建Context
const Context = createContext(null)

const DemoContextReducer = () => {
// 创建数据读写的API
const [state, dispatch] = useReducer(reducer, store)
return (
<Context.Provider value={{state, dispatch}}>
<User/>
<Books/>
<Movies/>
</Context.Provider>
)
}

const User = () => {
const {state, dispatch} = useContext(Context)
useEffect(() => {
ajax("/user").then(user => {
dispatch({type: "setUser", user})
console.log(user)
})
}, [])
return (
<>
<h3>姓名</h3>
{state.user ? <div>{state.user.name}</div> : null}
</>
)
}
const Books = () => {
const {state, dispatch} = useContext(Context)
useEffect(() => {
ajax("/books").then(books => {
dispatch({type: "setBooks", books})
})
}, [])
return (
<>
<h3>书籍</h3>
{state.books ? state.books.map(book => (<div key={book.id}>{book.name}</div>)) : null}
</>
)
}
const Movies = () => {
const {state, dispatch} = useContext(Context)
useEffect(() => {
ajax("/movies").then(movies => {
dispatch({type: "setMovies", movies: movies})
})
}, [])
return (
<div>
<h3>电影</h3>
{state.movies ? state.movies.map(item => <div key={item.id}>{item.name}</div>) : null}
</div>
)
}

export default DemoContextReducer

// 模拟请求数据
function ajax(path) {
return new Promise((resolve, reject) => {
setTimeout(() => {
if (path === "/user") {
resolve({
id: 1,
name: "梁又文"
})
} else if (path === "/books") {
resolve([{
id: 1,
name: "我是一本好书"
}, {
id: 2,
name: "我是一本坏书"
}])
} else if (path === "/movies") {
resolve([{
id: 1,
name: "最时间的尽头"
}, {
id: 2,
name: "八百"
}])
}
}, 3000)
})
}

拓展二、自定义hook

代码示例

useList

1
2
3
4
5
6
7
8
9
10
11
import {useState} from "react"

const useList = () => {
const [list, setList] = useState(0)
return ({
list: list,
setList: setList
})
}

export default useList

DemoCustomHook

1
2
3
4
5
6
7
8
9
10
11
12
13
14
import React from "react"
import useList from "./hooks/useList"

const DemoCustomHook = () => {
const {list, setList} = useList()
return (
<>
<div>{list}</div>
<button onClick={() => setList(n => n + 10)}>+10</button>
</>
)
}

export default DemoCustomHook