一、 基本配置
- 安装 redux 和 react-redux
npm i redux react-redux --save
- src 下创建 store 目录,新建 index.ts
import { legacy_createStore} from "redux";
import reducer from "./reducer";
让浏览器redux-dev-tools能正常使用
const store = legacy_createStore(reducer,window.__REDUX_DEVTOOLS_EXTENSION__ &&
window.__REDUX_DEVTOOLS_EXTENSION__());
export default store
- 创建一个提供数据的 reducer.tsx
const initialState = {
num: 20,
}
export default (state = initialState) => {
let newState = JSON.parse(JSON.stringify(initialState))
return newState
}
- main.tsx 文件中通过 Provider 组件进行包裹 App 组件进行提供数据
import { Provider } from 'react-redux'
import store from '@/store'
ReactDOM.createRoot(document.getElementById('root') as HTMLElement).render(
<Provider store={store}>
<React.StrictMode>
<BrowserRouter>
<App />
</BrowserRouter>
</React.StrictMode>
</Provider>,
)
二、 语法
1. 获取数据
import { useSelector } from 'react-redux'
const { num } = useSelector((state: { num: number }) => ({ num: state.num }))
2. 修改数据
export default (state = initialState, action: { type: string; val: any }) => {
let newState = JSON.parse(JSON.stringify(state))
switch (action.type) {
case 'add':
newState.num++
break
case 'add2':
newState.num += action.val
break
default:
break
}
return newState
}
import { useSelector, useDispatch } from 'react-redux'
const dispatch = useDispatch()
const changeNum = () => {
dispatch({ type: 'add2', val: 7 })
}
三、模块化
- store 文件夹下创建对应的模块文件夹
- 模块文件下创建 index(管理数据)和 reducer(处理数据) 文件
const store = {
state: {
num: 18,
},
actions: {
add(state: { num: any }, action: object) {
state.num++
},
},
}
export default store
const store = {
state: {
num: 20,
},
actions: {
add2(state: { num: any }, { type, val }: any) {
state.num += val
},
},
}
export default store
import store from '.'
export default (
state = { ...store.state },
action: { type: string; val: any },
) => {
let newState = JSON.parse(JSON.stringify(state))
for (let key in store.actions) {
if (action.type === key) {
store.actions[key](newState, action)
break
}
}
return newState
}
- store 文件夹下的 index 文件将模块进行整合、注册
import { combineReducers, legacy_createStore } from 'redux'
import reducer1 from './Data/reducer'
import reducer2 from './Data1/reducer'
const reducers = combineReducers({
reducer1,
reducer2,
})
const store = legacy_createStore(
reducers,
window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__(),
)
export default store
- 访问的话通过 useSelector 方法返回对应 模块 的数据(state.模块名.xxx)
const { num } = useSelector((state: RootState) => ({
num: state.reducer1.num,
}))
const { num: num2 } = useSelector((state: RootState) => ({
num: state.reducer2.num,
}))
四、异步解决
1. 问题
- 在store/NumStatus/index.ts中做异步操作
- 会发现这种写法其实达不到想要的异步效果
- 需要通过 redux 相关的异步方案来解决
add1(newState:{num:number},action:{type:string}){
setTimeout(()=>{
newState.num++;
},1000)
},
2. redux-thunk
- 市面上有redux- saga , redux-thunk,redux-thunk相比于redux-saga ,体积小,灵活,但需要自己手动抽取和封装。但学习成本较低。
- 安装:npm i redux-thunk
- 让 redux 调式工具兼容异步
- 导入 applyMiddleware、compose 方法将仓库数据、reduxTools、reduxThunk 进行关联
- 给 dispatch 方法传递一个执行异步的回调
- 执行回调中传递的参数,根据 tyep 标记去匹配需要执行的方法
import {
combineReducers,
legacy_createStore,
compose,
applyMiddleware,
} from 'redux'
import reducer1 from './Data/reducer'
import reducer2 from './Data1/reducer'
import reduxThunk from 'redux-thunk'
const reducers = combineReducers({
reducer1,
reducer2,
})
let composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__
? window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__({})
: compose
const store = legacy_createStore(
reducers,
composeEnhancers(applyMiddleware(reduxThunk)),
)
export default store
import store from '@/store/Data'
dispatch(store.asyncFun.asyncAdd)
{
state: {
num: 18,
},
actions: {
add(state: { num: number }, action: object) {
state.num++
},
},
asyncFun: {
asyncAdd(disp: Function) {
setTimeout(() => {
disp({ type: 'add' })
}, 1000)
},
},
}