每天对自己多问几个为什么,总是有着想象不到的收获。 一个菜鸟小白的成长之路(copyer)
公司一直用的是mobx,感觉自己好久没有动过redux了,正好自己有点空闲时间,就来回忆一下redux的搭建流程。
安装:
npx create-react-app <项目名> --template typescript //创建一个react项目
npm install redux react-redux --save //安装 redux react-redux
npm install @types/react-redux --save-dev //安装ts类型检测
目录划分:
这是我大致的划分目录,这是参考
---src
------store //存放store的根目录
---------count //count模块
-------------actions.ts //action
-------------constants.ts //常量
-------------index.ts //count的入口文件
-------------reducer.ts //reducer
-------------types.ts //用来存放count模块中的类型限定
---------index.ts //store的入口文件
---------reducer.ts //合并所有的reducer
------App.tsx //根组件
------index.tsx //项目的入口文件
store的入口文件 index.ts, 一般用于导出store对象,如果是ts的话,导出总的store的类型。
创建一个store对象,需要用到 redux中的createStore
这个方法
//分析createStore的参数
function createStore(reducer, preloadedState, enhancer) {}
第一个参数: 合并的reducer
第二个参数: initState的默认值(可选)
第三个参数: 加强函数(处理中间件)
// store/index.ts
import { createStore } from 'redux'
import reducer from './reducer'
//到合并的reducer类型
import { IRootReducer } from './reducer'
const store = createStore(reducer)
export default store
//导出reducer类型,在组件中: useSelector的时候使用
export type { IRootReducer }
redux这个库提供一个函数 专门用来 合并 reducer -------combineReducers
类型分析:
export function combineReducers<S>(
reducers: ReducersMapObject<S, any>
): Reducer<CombinedState<S>>
接受一个泛型: S
代表合并state的类型
//reducer.ts
import { combineReducers } from "redux"
import countReducer from "./count"
import { IInitCountState } from "./count/types"
export interface IRootReducer { //合并reducer之后,state的类型
countReducer: IInitCountState
}
const rootReducer = combineReducers<IRootReducer>({
countReducer
})
export default rootReducer
这里我是用来专门处理 导出 reducer 和 所以 action的createor
//导入reducer
import countReducer from "./reducer"
//导出action
import { addAction, subAction } from "./action"
//导出action
export { addAction, subAction }
//导出reducer
export default countReducer
常量主要在action 和 reducer中使用
export const ADD = "ADD" //加
export const SUB = "SUB" //减
存放类型接口
export interface IInitCountState {
count: number
}
export interface IAction {
type: string
[index: string]: any
}
reducer必须保证是一个纯函数
import { IInitCountState, IAction } from "./types"
import { ADD, SUB } from "./constants"
const initState: IInitCountState = {
count: 0
}
const countReducer = (state = initState, action: IAction): IInitCountState => {
switch(action.type) {
case ADD: {
return {...state, count: state.count + action.count}
}
case SUB: {
return {...state, count: state.count - action.count}
}
default: {
return { ...state }
}
}
}
export default countReducer
import { ADD, SUB } from "./constants"
import { IAction } from "./types"
export function addAction(count: number): IAction {
return {
type: ADD,
count
}
}
export function subAction(count: number): IAction {
return {
type: SUB,
count
}
}
以上store的基本任务就完成了,接下来就是在组件中使用了。在项目的入口文件,需要注册整个store到项目中。 利用react-redux
中 Provider
Provider主要原理就是react的context实现
import React from 'react'
import ReactDOM from 'react-dom'
import './index.css'
import App from './App'
import store from '@/store'
import { Provider } from 'react-redux' //导入Provider组件
ReactDOM.render(
<Provider store={store}> //注入全局store
<App />
</Provider>,
document.getElementById('root')
)
这里也主要利用 react-redux
提供的两个hooks函数 useSelector 和 useDispatch
import React from 'react';
import { Button } from 'antd'
import { useSelector, useDispatch } from 'react-redux' //导入两个hooks
import { IRootReducer } from '@/store' //导入store的入口文件的state的类型
//导入 count中的两个actionCreator
import { addAction, subAction } from '@/store/count'
function App() {
const dispatch = useDispatch() //拿到store中的dispatch函数,触发action
const count = useSelector((state: IRootReducer) => { //拿到store中的state
return state.countReducer.count
})
const add = () => {
dispatch(addAction(10)) //点击触发action
}
const sub = () => {
dispatch(subAction(10))
}
return (
<div className="App">
<h1>{count}</h1>
<Button onClick={add}>加</Button>
<Button onClick={sub}>减</Button>
</div>
);
}
export default App;
以上,就是react + redux + react-redux + ts 的使用基本流程了。