typescript版的redux(结合hooks)使用
1.安装redux全家桶
这里需要注意react-redux的版本以及redux-thunk的版本,不然会出现什么类型不对,或者无提示的bug
npm i redux @types/redux redux-devtools-extension
npm i redux-thunk@2.3.0
npm i react-redux@7
文件目录如下
store/index.ts文件内容
import { applyMiddleware, legacy_createStore } from 'redux'
import { composeWithDevTools } from 'redux-devtools-extension'
import thunk, { ThunkAction } from 'redux-thunk'
import RootReducer from './reducers'
import { todoAction } from './actions/todos'
const middleWare = [thunk]
const store = legacy_createStore(
RootReducer,
composeWithDevTools(applyMiddleware(...middleWare))
)
// 后续有多个action的话直接用联合类型运算符| 如=》todoAction | myAction
export type RootAction = todoAction
// ReturnType返回state的类型
// 导出这个供给useSelector使用,见官网链接 https://redux.js.org/usage/usage-with-typescript#typing-the-useselector-hook
export type RootState = ReturnType<typeof store.getState>
export type AppDispatch = typeof store.dispatch
// 主要是给异步action使用,返回值的类型需要这个
// 见文档https://redux.js.org/usage/usage-with-typescript#type-checking-redux-thunks
export type RootThunkAction = ThunkAction<void, RootState, unknown, RootAction>
export default store
store/reducers/index.ts内容
import { combineReducers } from "redux";
import todos from './todos'
export default combineReducers({
todos
})
store/reducers/todo.ts内容
import { todoAction } from '../actions/todos'
export type TodosType = {
id: number
name: string
done: boolean
}[]
const initValue: TodosType = []
export default function todos (state = initValue, action: todoAction) {
switch (action.type) {
case 'todo/gettodos': {
return action.payload
}
default: {
return state
}
}
}
store/actions/todos.ts内容
import { RootThunkAction } from '..'
import { TodosType } from '../reducers/todos'
export type todoAction = {
type: 'todo/gettodos'
payload: TodosType
}
// 固定返回值,需要是RootThunkAction
export const getTodos = (): RootThunkAction => {
return async dispatch => {
// 这里模拟axios请求,所以res直接给any了
const res:any = await new Promise(resolve=>{
setTimeout(() => {
return resolve({"data":{"channels":[{"id":0,"name":"推荐"},{"id":1,"name":"html"},{"id":2,"name":"开发者资讯"},{"id":4,"name":"c++"},{"id":6,"name":"css"},{"id":7,"name":"数据库"},{"id":8,"name":"区块链"},{"id":9,"name":"go"},{"id":10,"name":"产品"},{"id":11,"name":"后端"},{"id":12,"name":"linux"},{"id":13,"name":"人工智能"},{"id":14,"name":"php"},{"id":15,"name":"javascript"},{"id":16,"name":"架构"},{"id":17,"name":"前端"},{"id":18,"name":"python"},{"id":19,"name":"java"},{"id":20,"name":"算法"},{"id":21,"name":"面试"},{"id":22,"name":"科技动态"},{"id":23,"name":"js"},{"id":24,"name":"设计"},{"id":25,"name":"数码产品"},{"id":26,"name":"软件测试"}]},"message":"OK"})
}, 200);
})
dispatch({
type: 'todo/gettodos',
payload: res.data.channels
})
}
}
App.tsx文件:
import { useEffect } from 'react'
import { useDispatch, useSelector } from 'react-redux'
import { RootState } from './store'
import { getTodos } from './store/actions/todos'
function App () {
const state = useSelector((state: RootState) => state.todos)
const dispatch = useDispatch()
useEffect(() => {
dispatch(getTodos())
}, [])
return (
<div className='App'>
<ul>
{state.map(item => (
<li key={item.id}>{item.name}</li>
))}
</ul>
</div>
)
}
export default App
最后,别忘了main.tsx中,把store挂载上去
import ReactDOM from 'react-dom'
import { Provider } from 'react-redux'
import App from './App'
import store from './store'
ReactDOM.render(
<Provider store={store}>
<App />
</Provider>,
document.getElementById('root')
)
此时页面加载就会自动调用dispatch发起请求获取数据,然后存到redux,控制台的redux插件可以看