React学习

useEffect

是每次组件 render 完后判断依赖并执行

useCallback缓存一个函数

1
2
3
4
5
6
7
8
9
function Counter() {
const [count, setCount] = useState(0);
const handleIncrement = useCallback(
() => setCount(count + 1),
[count], // 只有当 count 发生变化时,才会重新创建回调函数
);
// ...
return <button onClick={handleIncrement}>+</button>
}

useMemo 缓存的是计算的结果

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
export default function SearchUserList() {
const [users, setUsers] = useState(null);
const [searchKey, setSearchKey] = useState("");
useEffect(() => {
const doFetch = async () => {
// 组件首次加载时发请求获取用户数据
const res = await fetch("https://reqres.in/api/users/");
setUsers(await res.json());
};
doFetch();
}, []);

// let usersToShow = null;
// if (users) {
// // 无论组件为何刷新,这里一定会对数组做一次过滤的操作
// usersToShow = users.data.filter((user) =>
// user.first_name.includes(searchKey),
// );
// }

const usersToShow = useMemo(() => {
if (!users) return null;
return users.data.filter((user) => {
return user.first_name.includes(searchKey);
})
,
[users, searchKey]);

return (
<div>
<input
type="text"
value={searchKey}
onChange={(evt) => setSearchKey(evt.target.value)}
/>
<ul>
{usersToShow &&
usersToShow.length > 0 &&
usersToShow.map((user) => {
return <li key={user.id}>{user.first_name}</li>;
})}
</ul>
</div>
);
}

使用useMemo当作useCallback()

1
2
3
4
5
6
const myEventHandler = useMemo(() => {
// 返回一个函数作为缓存结果
return () => {
// 在这里进行事件处理
}
}, [dep1, dep2]);

useRef 在函数组件之外创建的一个容器空间 通过唯一的 current 属设置一个值,从而在函数组件的多次渲染之间共享这个值

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
export default function Timer() {
// 定义 time state 用于保存计时的累积时间
const [time, setTime] = useState(0);
// 定义 timer 这样一个容器用于在跨组件渲染之间保存一个变量
const timer = useRef(null);
// 开始计时的事件处理函数
const handleStart = useCallback(() => {
// 使用 current 属性设置 ref 的值
timer.current = window.setInterval(() => {
setTime((time) => time + 1);
}, 100);
}, []);
// 暂停计时的事件处理函数
const handlePause = useCallback(() => {
// 使用 clearInterval 来停止计时
window.clearInterval(timer.current);
timer.current = null;
}, []);
return (
<div>
{time / 10} seconds.
<br />
<button onClick={handleStart}>Start</button>
<button onClick={handlePause}>Pause</button>
</div>
);
}

useContext:定义全局状态

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
const themes = {
light: {
foreground: "#000000",
background: "#eeeeee"
},
dark: {
foreground: "#ffffff",
background: "#222222"
}
};
// 创建一个 Theme 的 Context
const ThemeContext = React.createContext(themes.light);
function App() {
const [theme, setTheme] = useState("dark")

const toggleTheme = () => {
const newTheme = theme === 'dark' ? 'light': 'dark'
setTheme(newTheme)
}

// 整个应用使用 ThemeContext.Provider 作为根组件
return (
// 使用 themes.dark 作为当前 Context
<ThemeContext.Provider value={themes[them]}>
<button onClick={toggleTheme}>Toggle Theme</button>
<Toolbar />
</ThemeContext.Provider>
);
}
// 在 Toolbar 组件中使用一个会使用 Theme 的 Button
function Toolbar(props) {
return (
<div>
<ThemedButton />
</div>
);
}
// 在 Theme Button 中使用 useContext 来获取当前的主题
function ThemedButton()
const theme = useContext(ThemeContext);
return (
<button style={{
background: theme.background,
color: theme.foreground
}}>
I am styled by theme context!
</button>
);
}

自定义hook

使用use开头

使用了其他hook

定义useAsync

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
export const useAsync = (asyncFunction: any) => {
// 设置三个异步逻辑相关的 state
const [data, setData] = useState<any>(null);
const [loading, setLoading] = useState(false);
const [error, setError] = useState(null);
// 定义一个 callback 用于执行异步逻辑
const execute = useCallback(() => {
// 请求开始时,设置 loading 为 true,清除已有数据和 error 状态
setLoading(true);
setData(null);
setError(null);
return asyncFunction()
.then((response: any) => {
// 请求成功时,将数据写进 state,设置 loading 为 false
setData(response);
setLoading(false);
})
.catch((error: any) => {
// 请求失败时,设置 loading 为 false,并设置错误状态
setError(error);
setLoading(false);
});
}, [asyncFunction]);
return { execute, loading, data, error };
};

export default function UserList() {
// 定义获取用户的回调函数
const fetchUsers = async () => {
const res = await fetch("https://reqres.in/api/users/");
const result = await res.json();
return result.data
// 请求成功后将用户数据放入 state
};

const {execute, loading, data: users, error} = useAsync(fetchUsers)

return (
<div className="user-list">
<button onClick={() => { execute() }} disabled={loading}>
{loading ? "Loading..." : "Show Users"}
</button>
{error &&
<div style={{ color: "red" }}>Failed: {String(error)}</div>
}
<br />
<ul>
{users && users.length > 0 &&
users.map((user: any) => {
return <li key={user.id}>{user.first_name}</li>;
})}
</ul>
</div>
);
}

自定义useForm

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
import { useCallback, useState } from "react"

interface FormState {
[key: string]: string
}

interface Validatetor {
[key: string]: (value: string) => String | null
}

interface Errors {
[key: string]: String | null
}

export const useForm = (initialState: FormState, validatetor: Validatetor) => {
const [values, setValues] = useState(initialState)
const [erros, setErros] = useState<Errors>({})

const setFileValues = useCallback((name: string, value: string)=>{
setValues((values) => (
{
...values,
[name]: value
}
))

setErros(erros => ({
...erros,
[name]: validatetor[name](value)

}))

}, [])

return {
values,
erros,
setFileValues
}
}

export const MyForm = () => {

const validators = useMemo(() => {
return {
name: (value: string) => {
// 要求 name 的长度不得小于 2
if (value.length < 2) return "Name length should be no less than 2.";
return null;
},
email: (value: string) => {
// 简单的实现一个 email 验证逻辑:必须包含 @ 符号。
if (!value.includes("@")) return "Invalid email address";
return null;
},
};
}, []);

const { values, erros, setFileValues } = useForm({}, validators)

const handleSubmit = (e: FormEvent) => {
e.preventDefault()
console.log(values)
}


return (
<form onSubmit={e => handleSubmit(e)}>
<div>
<label htmlFor="用户名"></label>
<input type="text" value={values.name || ''} onChange={(e) => { setFileValues('name', e.target.value) }} />
{
erros.name &&
<div style={{color: 'red'}}>
{erros.name}
</div>
}
</div>
<div>
<label htmlFor="昵称"></label>
<input type="text" value={values.email || ''} onChange={(e) => { setFileValues('email', e.target.value) }} />
{
erros.email &&
<div style={{color: 'red'}}>
{erros.email}
</div>
}
</div>
<button type="submit">提交</button>
</form>
)
}

作者

建指所向

发布于

2022-09-19

更新于

2023-11-07

许可协议