跳到主要内容

useReducer

1.是什么

更高级版的 useState ,它主要解决:状态逻辑越来越复杂,多个状态之间互相关联,更新逻辑难维护 的问题。

#起初
const [count, setCount] = useState(0);

#项目复杂后
const [name, setName] = useState("");
const [age, setAge] = useState(18);
const [loading, setLoading] = useState(false);
const [error, setError] = useState(null);
const [list, setList] = useState([]);

#此时的问题:状态越来越散,状态修改逻辑到处都是

setLoading(true);
fetchData()
.then(res => {
setList(res);
setLoading(false);
})
.catch(err => {
setError(err);
setLoading(false);
});

#逻辑开始混乱
#此时若你想进行”集中管理状态更新“,你就需要用到它

2.使用方法

#解释
function reducer(state, action)
state 当前状态
action 要执行的动作

const [count, dispatch] = useReducer(reducer, 0);
#dispatch({ type: "increment" }) 要发送一个动作
#react内部流程
1.dispatch
2.调用 reducer(state,action)
3.得到 newState
4.组件重新渲染

#写法
import { useReducer } from "react";

function reducer(state, action) {
switch (action.type) {
case "increment":
return state + 1;

case "decrement":
return state - 1;

default:
return state;
}
}

function App() {
const [count, dispatch] = useReducer(reducer, 0);

return (
<>
<h1>{count}</h1>

<button onClick={() => dispatch({ type: "increment" })}>
+1
</button>

<button onClick={() => dispatch({ type: "decrement" })}>
-1
</button>
</>
);
}



3.高频应用场景

3.1 请求状态管理(loading / data / error)

如请求用户列表页面需要管理loading,error,data。所有状态更新逻辑都集中在reducer,代码结构清晰。

使用useState:

function UserList() {
const [loading, setLoading] = useState(false);
const [data, setData] = useState([]);
const [error, setError] = useState(null);

const fetchUsers = async () => {
try {
setLoading(true);
setError(null);

const res = await fetch("/api/users");
const result = await res.json();

setData(result);
} catch (err) {
setError("请求失败");
} finally {
setLoading(false);
}
};

return (
<div>
<button onClick={fetchUsers}>
获取用户
</button>

{loading && <p>加载中...</p>}

{error && <p>{error}</p>}

{data.map(user => (
<div key={user.id}>
{user.name}
</div>
))}
</div>
);
}

使用useReducer:

#第一步:定义初始状态
const initialState = {
loading: false,
data: [],
error: null
};

#第二步:定义 reducer
function reducer(state, action) {
switch (action.type) {

case "FETCH_START":
return {
...state,
loading: true,
error: null
};

case "FETCH_SUCCESS":
return {
loading: false,
data: action.payload,
error: null
};

case "FETCH_ERROR":
return {
loading: false,
data: [],
error: action.payload
};

default:
return state;
}
}

#第三步:使用 useReducer
import { useReducer } from "react";
function UserList() {
const [state, dispatch] = useReducer(
reducer,
initialState
);

const fetchUsers = async () => {

dispatch({
type: "FETCH_START"
});

try {
const res = await fetch("/api/users");
const result = await res.json();

dispatch({
type: "FETCH_SUCCESS",
payload: result
});

} catch (err) {

dispatch({
type: "FETCH_ERROR",
payload: "请求失败"
});
}
};

return (
<div>
<button onClick={fetchUsers}>
获取用户
</button>

{state.loading && <p>加载中...</p>}

{state.error && <p>{state.error}</p>}

{state.data.map(user => (
<div key={user.id}>
{user.name}
</div>
))}
</div>
);
}

3.2 购物车(添加/删除商品,增加/减少数量,清空购物车)

#购物车数据
const initialState = {
cart: []
};

#reducer
function reducer(state, action) {

switch (action.type) {

case "ADD_ITEM":

const exist = state.cart.find(
item => item.id === action.payload.id
);

// 已存在 -> 数量+1
if (exist) {

return {
cart: state.cart.map(item =>
item.id === action.payload.id
? {
...item,
count: item.count + 1
}
: item
)
};
}

// 不存在 -> 新增
return {
cart: [
...state.cart,
{
...action.payload,
count: 1
}
]
};

case "REMOVE_ITEM":

return {
cart: state.cart.filter(
item => item.id !== action.payload
)
};

case "INCREMENT":

return {
cart: state.cart.map(item =>
item.id === action.payload
? {
...item,
count: item.count + 1
}
: item
)
};

case "DECREMENT":

return {
cart: state.cart.map(item =>
item.id === action.payload
? {
...item,
count: item.count - 1
}
: item
)
};

case "CLEAR_CART":

return {
cart: []
};

default:
return state;
}
}
#组件使用
import { useReducer } from "react";

function Cart() {

const [state, dispatch] = useReducer(
reducer,
initialState
);

const product = {
id: 1,
name: "iPhone"
};

return (
<div>

<button
onClick={() =>
dispatch({
type: "ADD_ITEM",
payload: product
})
}
>
添加商品
</button>

{state.cart.map(item => (
<div key={item.id}>

<h3>
{item.name}
</h3>

<p>
数量:{item.count}
</p>

<button
onClick={() =>
dispatch({
type: "INCREMENT",
payload: item.id
})
}
>
+
</button>

<button
onClick={() =>
dispatch({
type: "DECREMENT",
payload: item.id
})
}
>
-
</button>

<button
onClick={() =>
dispatch({
type: "REMOVE_ITEM",
payload: item.id
})
}
>
删除
</button>

</div>
))}

<button
onClick={() =>
dispatch({
type: "CLEAR_CART"
})
}
>
清空购物车
</button>

</div>
);
}