ReactWheels07-03Hooks全解1

代码仓库

React Hooks

  • 状态:useState
  • 副作用: useEffect
    • useLayoutEffect
  • 上下文: useContext
  • Redux : useReducer
  • 记忆: useMemo
    • useCallback
  • 引用: useRef
    • useImperativeHandle
  • 自定义Hook
    • useDebugValue

useState

1
2
3
// 使用
const [n, setN] = useState(0);
const [user, setUser] = useState({name:'f'});

注意事项:不能局部更新

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
const [user, setUser] = useState({name:'f',age:19});

onClick(){
setUser({
age:20
})
}

// 这样操作之后, name属性就没了

你只能这样

onClick(){
setUser({
...user,
age:20
})
}

注意事项2:不能直接改地址

1
2
3
4
5
6
7
const [user, setUser] = useState({name:'f',age:19});

onClick(){
user.name = 'xxx' // 千万不要改之前的对象
setUser(user)
// 这样也不会触发更新
}

useState补充

  • useState接受函数
1
2
3
4
5
6
7
8
9
10
// 这样每次 js解析 都会 算一下 18+18
const [user,setUser] = useState({name:'aaa',age:18+18})

对比这样的好处是 函数只会执行一次,减少多余的计算过程
const [user,setUser] = useState(()=>{
return ({name:'aaa',age:18+18})
})


// 基本用不到
  • setState 可以用函数
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
const [n, setN] = useState(0);

onClick(){
setN(n+1) // n不会变
setN(n+2) // 只有最后一次会生效
// n = 2
}


// 多次操作n的正确姿势
onClick(){
setN(x => x+1)
setN(y => y+1)
// n = 2
}

useReducer

  • 用来践行 Flue/Redux思想 一共四步
    • 创建 initState
    • 创建所有 reducer(state,action)
    • 传给 useReducer ,得到 读/写 api
    • 调用写 {type:'操作类型'}
  • useReducer 就是 useState的复杂版

  • 代码

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
import React, { useState, useReducer } from "react";
import ReactDOM from "react-dom";

// 1创建初始值
const initial = {
n: 0
};

// 2创建所有 reducer
const reducer = (state, action) => {
if (action.type === "add") {
return { n: state.n + action.number };
} else if (action.type === "multi") {
return { n: state.n * 2 };
} else {
throw new Error("unknown type");
}
};

function App() {
const [state, dispatch] = useReducer(reducer, initial);
const { n } = state;
const onClick = () => {
dispatch({ type: "add", number: 1 });
};
const onClick2 = () => {
dispatch({ type: "add", number: 2 });
};
return (
<div className="App">
<h1>n: {n}</h1>
<button onClick={onClick}>+1</button>
<button onClick={onClick2}>+2</button>
</div>
);
}

const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
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
import React, { useReducer } from "react";
import ReactDOM from "react-dom";

const initFormData = {
name: "",
age: 18,
nationality: "汉族"
};

function reducer(state, action) {
switch (action.type) {
case "patch":
return { ...state, ...action.formData };
case "reset":
return initFormData;
default:
throw new Error();
}
}

function App() {
const [formData, dispatch] = useReducer(reducer, initFormData);
// const patch = (key, value)=>{
// dispatch({ type: "patch", formData: { [key]: value } })
// }
const onSubmit = () => {};
const onReset = () => {
dispatch({ type: "reset" });
};
return (
<form onSubmit={onSubmit} onReset={onReset}>
<div>
<label>
姓名
<input
value={formData.name}
onChange={(e) =>
dispatch({ type: "patch", formData: { name: e.target.value } })
}
/>
</label>
</div>
<div>
<label>
年龄
<input
value={formData.age}
onChange={(e) =>
dispatch({ type: "patch", formData: { age: e.target.value } })
}
/>
</label>
</div>
<div>
<label>
民族
<input
value={formData.nationality}
onChange={(e) =>
dispatch({
type: "patch",
formData: { nationality: e.target.value }
})
}
/>
</label>
</div>
<div>
<button type="submit">提交</button>
<button type="reset">重置</button>
</div>
<hr />
{JSON.stringify(formData)}
</form>
);
}

const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);