【Redux】的封装以及使用(6)


一、 基本配置

  1. 安装 redux 和 react-redux
npm i redux react-redux --save
  1. src 下创建 store 目录,新建 index.ts
// 导入 redux 中的 legacy_createStore 来创建状态管理仓库
import { legacy_createStore} from "redux";
import reducer from "./reducer";
// window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__()
让浏览器redux-dev-tools能正常使用
const store = legacy_createStore(reducer,window.__REDUX_DEVTOOLS_EXTENSION__ &&
window.__REDUX_DEVTOOLS_EXTENSION__());
export default store
  1. 创建一个提供数据的 reducer.tsx
// 初始化 state
const initialState = {
  num: 20,
}

export default (state = initialState) => {
  // 将传递的数据进行深拷贝
  let newState = JSON.parse(JSON.stringify(initialState))

  // 返回 state
  return newState
}
  1. main.tsx 文件中通过 Provider 组件进行包裹 App 组件进行提供数据
// 通过 provider 提供数据
import { Provider } from 'react-redux'
import store from '@/store'

ReactDOM.createRoot(document.getElementById('root') as HTMLElement).render(
  // Provider 给所有组件提供 store 里的数据
  <Provider store={store}>
    <React.StrictMode>
      <BrowserRouter>
        <App />
      </BrowserRouter>
    </React.StrictMode>
  </Provider>,
)

二、 语法

1. 获取数据
import { useSelector } from 'react-redux'

// 通过 useSelector 方法,获取返回的 state 中的数据
const { num } = useSelector((state: { num: number }) => ({ num: state.num }))
2. 修改数据
// reducer.tsx

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
  }

  // 返回 state
  return newState
}

// page.tsx

import { useSelector, useDispatch } from 'react-redux'
// 通过 useDispatch 方法,修改 state 中的数据
const dispatch = useDispatch()

const changeNum = () => {
    // type 固定属性对应触发的函数名
    // val 自定义的属性
    // 该方法执行后 reducer 中的会对传递的 type 值进行判断执行对应的操作
    // dispatch({ type: 'add' })
    dispatch({ type: 'add2', val: 7 })
}

三、模块化

  1. store 文件夹下创建对应的模块文件夹
  2. 模块文件下创建 index(管理数据)和 reducer(处理数据) 文件
// 模块1 index
const store = {
  state: {
    num: 18,
  },
  actions: {
    add(state: { num: any }, action: object) {
      state.num++
    },
  },
}

export default store

// 模块2 index
const store = {
  state: {
    num: 20,
  },
  actions: {
    add2(state: { num: any }, { type, val }: any) {
      state.num += val
    },
  },
}

export default store

// reducer
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) {
    // 判断传递的方法在 store 中是否存在
    if (action.type === key) {
      // 存在则调用对应的方法
      store.actions[key](newState, action)
      break
    }
  }

  // 返回 state
  return newState
}
  1. store 文件夹下的 index 文件将模块进行整合、注册
import { combineReducers, legacy_createStore } from 'redux'
// reducer 导入准备的数据
import reducer1 from './Data/reducer'
import reducer2 from './Data1/reducer'

// 组个各个模块的 reducer
const reducers = combineReducers({
  reducer1,
  reducer2,
})

// 创建数据仓库,注册 reducer
const store = legacy_createStore(
  reducers,
  window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__(),
)
// 导出
export default store
  1. 访问的话通过 useSelector 方法返回对应 模块 的数据(state.模块名.xxx)
// 通过 useSelector 方法,获取返回的 state 中的数据
const { num } = useSelector((state: RootState) => ({
    // 模块1的 num
    num: state.reducer1.num,
}))
const { num: num2 } = useSelector((state: RootState) => ({
    // 模块2的 num
    num: state.reducer2.num,
}))

四、异步解决

1. 问题
  1. 在store/NumStatus/index.ts中做异步操作
  2. 会发现这种写法其实达不到想要的异步效果
  3. 需要通过 redux 相关的异步方案来解决
add1(newState:{num:number},action:{type:string}){
    //newState.num++;
    // 会有bug 没有办法达到延迟和修改的效果
    setTimeout(()=>{
        newState.num++;
    },1000)
},
2. redux-thunk
  1. 市面上有redux- saga , redux-thunk,redux-thunk相比于redux-saga ,体积小,灵活,但需要自己手动抽取和封装。但学习成本较低。

  2. 安装:npm i redux-thunk

  3. 让 redux 调式工具兼容异步

  4. 导入 applyMiddleware、compose 方法将仓库数据、reduxTools、reduxThunk 进行关联

  5. dispatch 方法传递一个执行异步的回调

  6. 执行回调中传递的参数,根据 tyep 标记去匹配需要执行的方法

// store/index
import {
  combineReducers,
  legacy_createStore,
  compose,
  applyMiddleware,
} from 'redux'
// reducer 导入准备的数据
import reducer1 from './Data/reducer'
import reducer2 from './Data1/reducer'
import reduxThunk from 'redux-thunk'

// 组个各个模块的 reducer
const reducers = combineReducers({
  reducer1,
  reducer2,
})

// 让 redux 调式工具兼容异步的处理
let composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__
  ? window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__({})
  : compose

// 把仓库数据,浏览器redux-dev-tools,还有reduxThunk插件关联在store中
const store = legacy_createStore(
  reducers,
  composeEnhancers(applyMiddleware(reduxThunk)),
)
// 导出
export default store


// page
import store from '@/store/Data'
// 异步的写法  redux-thunk 的用法  dispatch(异步执行的函数)
// disp 相当于 dispatch 用来标记调用的函数
// dispatch((disp: Function) => {
//   setTimeout(() => {
//     disp({ type: 'add' })
//   }, 0)
// })

// 优化 redux-thunk 的异步方法
// dispatch(调用状态管理中的 asyncAdd)
dispatch(store.asyncFun.asyncAdd)


// Data/index
{
  state: {
    num: 18,
  },
  actions: {
    add(state: { num: number }, action: object) {
      state.num++
    },
  },
  // 优化 redux-thunk 的异步方法(模仿 vuex 写法 )
  // 存放异步的方法
  asyncFun: {
    asyncAdd(disp: Function) {
      setTimeout(() => {
        disp({ type: 'add' })
      }, 1000)
    },
  },
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值