在react + typescript项目中正确使用useReducer
我们在Home页面增加一个组件Counter,用来保存一个数值count,来记录点击按钮的次数,如下:
// Counter.tsx
import React, { useReducer } from 'react'
type StateType = {
count: number;
}
type ActionType = {
type: string;
payload: number;
}
const initialState = {count: 0}
function countReducer(state: StateType, action: ActionType) {
switch (action.type) {
case 'increment':
return {count: state.count + action.payload}
break;
case 'decrement':
return {count: state.count - action.payload}
break;
default:
return state
break;
}
}
export default function Counter() {
const [state, dispatch] = useReducer(countReducer, initialState)
const _increment = () => {
dispatch({
type: 'increment',
payload: 1
})
}
const _decrement = () => {
dispatch({
type: 'decrement',
payload: 1
})
}
return (
<div>
<p>Your count is {state.count}</p>
<button onClick={_increment}>increment</button>
<button onClick={_decrement}>decrement</button>
</div>
)
}
在Home页面使用,如下:
// Home.tsx
import React from "react";
import Counter from "../components/Counter";
const Home = () => {
return (
<div>
<p>这是Home页面</p>
<Counter />
</div>
)
}
export default Home;
如果我们现在新增一种action的type,为重置按钮reset,即<button onClick={_reset}>reset</button>
;
reducer函数也要做出相应的改变,新增一个type时的处理:
case 'reset':
return initialState
break;
相应的reset函数为:
const _reset = () => {
dispatch({
type: 'reset'
})
}
这样写之后会有个问题,就是我们在调用_reset
函数时会报错,因为我们只传入了一个type参数,没有传payload,ts编译器会告诉我们这里类型不匹配,但是我们这个函数的功能是重置,也就是根本就不需要使用到参数payload,那么怎么办呢?我们这样可以来写ActionType:
type UpdateActionType = {
type: 'increment' | 'decrement';
payload: number;
}
type ResetActionType = {
type: 'reset';
}
type ActionType = UpdateActionType | ResetActionType;
这样一来,我们在增加、减少和重置的时候都会去匹配对应的类型,ts编译器也可以愉快的玩耍了。
完整代码如下:
// Counter.tsx
import React, { useReducer } from 'react'
type StateType = {
count: number;
}
type UpdateActionType = {
type: 'increment' | 'decrement';
payload: number;
}
type ResetActionType = {
type: 'reset';
}
type ActionType = UpdateActionType | ResetActionType;
const initialState = {count: 0}
function countReducer(state: StateType, action: ActionType) {
switch (action.type) {
case 'increment':
return {count: state.count + action.payload}
break;
case 'decrement':
return {count: state.count - action.payload}
break;
case 'reset':
return initialState
break;
}
}
export default function Counter() {
const [state, dispatch] = useReducer(countReducer, initialState)
const _increment = () => {
dispatch({
type: 'increment',
payload: 1
})
}
const _decrement = () => {
dispatch({
type: 'decrement',
payload: 1
})
}
const _reset = () => {
dispatch({
type: 'reset'
})
}
return (
<div>
<p>Your count is {state.count}</p>
<button onClick={_increment}>increment</button>
<button onClick={_decrement}>decrement</button>
<button onClick={_reset}>reset</button>
</div>
)
}
代码地址及文件路径
注:
本文代码github仓库地址:ts中正确使用useReducer
文件路径:src/components/Counter.tsx
。