Redux状态机

424 阅读6分钟

Redux状态机

类似vuex一样的状态机

redux集中式管理我们项目中所有的数据的, 这个redux不属于react,属于第三方的一个工具

你什么是需要用redux, 你的项目如果简单的, 你也不知道为什么会用,那就可以不用, 只要项目组件之间数据比较复杂的时候, 你才可能会用上, 一旦你引入redux 你的项目就会变得复杂

如下: 当你的数据流相当复杂的时候, 你可以借用redux

image-20230309231300700

使用redux

1. 安装

yarn add redux

2.使用

import {legacy_createStore as createStore} from 'redux'

通过createStore创建仓库
const store = createStore(reducer函数,仓库数据)

reducer函数, 专门用来处理数据的, 类似vuex里的mutaions函数, 属于干活的人

createStore接收2个参数,

第一个是reducer函数,用来处理数据

第二个参数是仓库的数据

3.reducer函数的使用

reducer函数会按照用户的指令, 然后做相应操作

// 处理数据 state :你仓库的数据
function reducerFun(state,actions){
    // actions 会有不同事件操作
    // ADD, Reduce
     switch(actions.type){
        case 'ADD':
           return {...state,count: state.count+1} 
        case 'REDUCE':
            return {...state,count: state.count-1} 
        default: return state
     }
}

4.页面如何获取仓库中的数据

引入store
import store from '../../../store'
在组件中通过getState()获取仓库中的数据
 // 拿数据 store
    useEffect(()=>{
        console.log(store);
        // 获取仓库中的数据  getState
        console.log(store.getState().count);
        
    },[])

5.如何修改仓库中的数据

11

通过dispatch, 用来发指令, 就是你让 reducer函数帮你做什么事情

<button onClick={addCount}>我要把仓库中的数据count+1</button>
 const addCount = ()=>{
        // 发了一个, 让reducer去帮你做count+1的工作
        store.dispatch({
            type:'ADD'
        })
}

6.如何在页面中实时的获取到仓库中的数据

订阅仓库数据的变化,通过subscribe

你在页面只需要订阅一次, 在useEffect的副作用函数, 监听到了后你可以拿到仓库中最新的数据赋值给你当前组件中的变量

useEffect(()=>{
        // 通过subscribe监听的方式可以获取到数据的改变
        store.subscribe(()=>{
            console.log(store.getState().count,'我的新数据');
            setCurCount(store.getState().count)
        })
 },[])

注意:你不能在模板中直接通过store.getState()获取到仓库中的实时数据

你在组件中通过set函数写入到当前组件的变量的时候, 会触发store仓库中数据的改变

仓库中的数据模块化

就是为了解决项目足够大的时候, 让我们数据分模块管理,更方便维护

combineReducers用来管理模块化中的多个reducers,把所有的reducer函数进行合并, 把合并后得到的reducers作为参数传给createStore

注意:在合并的时候, 前面的key就是你模块的名字, 和仓库中模块的名字保持一致

11

仓库中的数据

01

处理数据还是分别交给不同的reducer函数

user模块的数据交给userReducer管:

function userReducer(state,action){
    state = state || {}
    // 添加, 删除,修改 
    switch(action.type){
        case 'user/add':
             return {...state};
        default: return state
    }
}

product模块的数据交给productReducer来管

function productReducer(state={},action){
    // 添加, 删除,修改 
    switch(action.type){
        case 'product/add':
             return {...state};
        default: return state
    }
}

1. 如何获取模块化中的数据

store.getState().user
就相当于store.getState()可以拿到仓库中所有的数据, 然后再获取你要的模块的数据 store.getState().user

2.修改模块中的数据

通过在页面中使用store.dispatch发一个指令, 然后对应的reducer函数帮忙处理

 const updateUser = ()=>{
        // 发了一个, 让reducer去帮你做count+1的工作
        store.dispatch({
            type:'user/add',  // 对应user模块中的 user/add
            payload:{
                name:'xiaobo',
                age:10
            }
        })
}

3.实时获取模块中的数据

 store.subscribe(()=>{
     console.log(store.getState().user,'我的新数据');
})
如果你要在模板中显示仓库中的数据, 你在这里拿到后要赋值给组建中的某一个变量

4.通过中hooks实时获取store中的数据

import {Provider} from 'react-redux'

import {Provider} from 'react-redux'
import store from './store/index.js'

ReactDOM.createRoot(document.getElementById('root')).render(
    <Provider store={store}>
        <App />
    </Provider>
)

这一步可完全是react-redux的内容

  • useSelector 替代 mapStateToProps从store中提取state数据
  • useDispatch 替代 mapDispatchToProps从store中获取dispatch方法的引用
useDispatch:

使用这个 hook 能得到 redux store 的 dispatch 方法引用,通常用于“手动” dispatch action

const dispatch = useDispatch()
useSelector

组件可以通过useSelector访问store中释放的state数据

这个 hook 会订阅 redux store(牢记这点),所以每次 redux state有更新,useSelector() 里的 selector 就会重新计算一次返回新的结果,并重新渲染当前组件

import React from 'react'
import {useSelector,useDispatch} from 'react-redux'
export default function TodoList() {
  const dispatch = useDispatch();
  const state = useSelector((state)=>{
    return state.counter
  })
  return (
    <div>
     {count}
        <button onClick={()=>dispatch({type:'add',payload:10})}>增加</button>
        <button onClick={()=>dispatch({type:'reduce'})}>减少</button>
    </div>
  )
}

redux-toolkit

Redux Toolkit 是官方推荐的编写 Redux 逻辑的方法

在前面我们学习Redux的时候应该已经发现,redux的编写逻辑过于的繁琐和麻烦。

并且代码通常分拆在多个文件中(虽然也可以放到一个文件管理,但是代码量过多,不利于管理);

Redux Toolkit包旨在成为编写Redux逻辑的标准方式,从而解决上面提到的问题;

在很多地方为了称呼方便,也将之称为“RTK”;

redux-toolkit定为最佳redux使用方式,而且原来的createStore方法已经被标识为弃用。

Redux Toolkit的核心API主要是如下几个:

configureStore: 包装createStore以提供简化的配置选项和良好的默认值。它可以自动组合你的 slice reducer,添加你提供 的任何 Redux 中间件,redux-thunk默认包含,并启用 Redux DevTools Extension。

createSlice: 接受reducer函数的对象、切片名称和初始状态值,并自动生成切片reducer,并带有相应的actions。

createAsyncThunk: 接受一个动作类型字符串和一个返回承诺的函数,并生成一个pending/fulfilled/rejected基于该承诺分 派动作类型的 thunk

使用方法

1.安装

yarn add @reduxjs/toolkit react-redux

不再需要单独安装redux了

2.创建store

import {configureStore} from "@reduxjs/toolkit"
import countreducer from "./reducer"

// 这里一定要注意configureStore的参数, 接收一个对象, api是 reducer, reducer下面又是一个对象
const store = configureStore({
   reducer:{
    counter:countReducer
    // todo:todoReducer
   },
   devTools:true
})
// 调用rtk的configureStore方法,该方法相当于集成了
// redux和redux-redux的createStore、combineReducers、middleware、enhancers,
// 以及默认支持了扩展工具Redux DevTools。

export default store;

reducer 创建reducer,传递给combineReducers使用 middleware 中间件,传递给applyMiddleware使用 devTools 扩展工具,默认为true preloadedState 初始state值,传递给createStore enhancers 增强 store,传递给createStore

3.定义切切片slice

rtk引入了新的定义slice,它是应用中对action和reducer逻辑的整合,通过createSlice方法进行创建

import {createSlice} from '@reduxjs/toolkit'
// 创建 reducer ,具有模块化的reducer
const count = createSlice({
    name:'counter',
    initialState:{count:1},
    reducers:{
        add(state,{payload}){
            state.count = state.count+payload;
        },
        reduce(state,{payload}){
            state.count = state.count-payload;
        }
    }
})
//reducers当中的方法会放在counterSlice的actions中, 用于派发action
export const countAction = count.actions
// 注意: 导出的是reducer, 用于在index.js中对reducer进行组合
export default count.reducer;

可以看到这里对state进行了直接修改,表面看来是违背了redux禁止修改state原则,实际是因为引用了immer的库,总是返回一个安全的、不可变的更新值,极大的简化reducer的写法。注意该方式只能在createSlice和createReducer中编写。

Redux持久化

1. 安装

yarn add redux-persist

2.配置持久化

2.1 在store/index.js文件配置

import {persistReducer} from 'redux-persist'
//  存储机制,可换成其他机制,当前使用sessionStorage机制
import storageSession from 'redux-persist/lib/storage/session'
import thunk from 'redux-thunk'

let storeConfig = {
    key:'root',
    storage:storageSession,
    blacklist:[]  // reducer里不想持久化的名单
}

1

2.2 在入口文件main.jsx中添加PersistGate 配置

import store from './store/index.js'
// 持久化
import {PersistGate} from 'redux-persist/lib/integration/react'
import {persistStore} from 'redux-persist'  
const persistor = persistStore(store)  //使用persistStore持久化store

 <Provider store={store}>
        <PersistGate loading={null} persistor={persistor}>
            <App />
        </PersistGate>
</Provider>
PersistGate:接收persistor这个api的目的是持久化store