use*** 格式定义的函数是react hooks的规范
useEffect用于处理组件中的effect,通常用于请求数据,事件处理,订阅等相关操作
最后return的【返回函数】可以作为状态切换的默认执行函数,执行下一个effect之前执行上一个effect【返回的函数】
状态和状态更新函数来自与useState这个hooks,通过调用useState,来创建App组件的内部状态。初始状态是一个object,其中的hits为一个空数组
axios发起请求,使用useEffect来隔离副作用
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25import React, { useState } from 'react';
import axios from 'axios';
function App() {
const [data, setData] = useState({ hits: [] });
useEffect(()=>{
const fetchData = async(){
const result = await axios('xxx');
setData(result.data);
}
fetchData()
},[])
return (
<ul>
{data.hits.map(item => (
<li key={item.objectID}>
<a href={item.url}>{item.title}</a>
</li>
))}
</ul>
);
}
export default App;useEffect在组件mount时执行,但也会在组件更新时执行
如果在useEffect中请求数据并setData会触发渲染,导致死循环
所以需要传递一个空数组作为参数,避免在更新时触发useEffect,只会在mount挂载时执行一次第二参数用于监听指定变量的更新
如果参数中定义的变量更新了,则useEffect会再次执行async函数会隐式返回promise,但是useEffect不返回内容,所以需要用方法包装async
响应更新的例子,用户输入
1 | function App() { |
query的任何一次变动都会请求后端,这样会带来比较大的访问压力。这个时候我们需要引入一个按钮,点击这个按钮再发起请求(query改为search)
每次点击按钮时,会把search的值设置为query,这个时候我们需要修改useEffect中的依赖项为search,这样每次点击按钮,search值变更,useEffect就会重新执行,避免不必要的变更
因为组件首先会在mount时获取数据。所以简单点,直接将的要请求的后端URL设置为search state的初始值
如果useEffect中出现其他外部变量也需要放入依赖数组中,所以btn依赖的query也提取到btn中,不转入useEffect
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
37function App() {
const [data, setData] = useState({ hits: [] });
const [query, setQuery] = useState('redux');
const [url, setUrl] = useState(
'http://localhost/api/v1/search?query=redux',
);
useEffect(() => {
const fetchData = async () => {
const result = await axios(url);
setData(result.data);
};
fetchData();
}, [url]);
return (
<Fragment>
<input
type="text"
value={query}
onChange={event => setQuery(event.target.value)}
/>
<button type="button" onClick={() => setUrl(`http://localhost/api/v1/search?query=${query}`)}>
Search
</button>
<ul>
{data.hits.map(item => (
<li key={item.objectID}>
<a href={item.url}>{item.title}</a>
</li>
))}
</ul>
</Fragment>
);
}处理Loading和error
在请求后端数据,展现loading的状态
不需要再loading变更时重新调用useEffect
处理错误,使用useState来创建一个新的state,然后在useEffect中特定的位置来更新这个state
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
30function App() {
const [isLoading, setIsLoading] = useState(false);
useEffect(() => {
const fetchData = async () => {
setIsLoading(true);
const result = await axios(url);
setData(result.data);
setIsLoading(false);
};
fetchData();
}
return (
<Fragment>
{isLoading ? (
<div>Loading ...</div>
) : (
<ul>
{data.hits.map(item => (
<li key={item.objectID}>
<a href={item.url}>{item.title}</a>
</li>
))}
</ul>
)}
</Fragment>
)
}同名目录内有抽离自定义hooks组件的例子
使用useReducer整合逻辑使用了各种通过分离的state hooks来管理分散的:数据、状态,为了有关联的状态整合到一起,我们需要用到useReducer
useReducer 是一个轻量的redux,返回一个状态对象和一个可以改变状态对象的dispatch函数,dispatch函数接受action作为参数,action包含type和payload属性
useReducer将reducer函数和初始状态对象作为参数,即同时定义多个hooks
type属性告诉reducer需要应用哪个状态转换,并且reducer可以使用payload来创建新的状态
例子中的state是对象,导出时可以解构分离原有状态
取消数据请求,在请求还没有返回的时候卸载了组件会报错
1 | const dataFetchReducer = (state, action) => { |
1 | 在没有hooks时,创建class组件,性能的优化通过immutable比较, |