在react + typescript项目中正确使用useReducer
我们在Home页面增加一个组件Counter,用来保存一个数值count,来记录点击按钮的次数,如下:
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
| 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页面使用,如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| 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时的处理:
1 2 3
| case 'reset': return initialState break;
|
相应的reset函数为:
1 2 3 4 5
| const _reset = () => { dispatch({ type: 'reset' }) }
|
这样写之后会有个问题,就是我们在调用_reset
函数时会报错,因为我们只传入了一个type参数,没有传payload,ts编译器会告诉我们这里类型不匹配,但是我们这个函数的功能是重置,也就是根本就不需要使用到参数payload,那么怎么办呢?我们这样可以来写ActionType:
1 2 3 4 5 6 7 8 9 10
| type UpdateActionType = { type: 'increment' | 'decrement'; payload: number; }
type ResetActionType = { type: 'reset'; }
type ActionType = UpdateActionType | ResetActionType;
|
这样一来,我们在增加、减少和重置的时候都会去匹配对应的类型,ts编译器也可以愉快的玩耍了。
完整代码如下:
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
| 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
。