react-6-redux

137 阅读4分钟

redux

redux 是一个 react 的状态管理插件。

前言

1. 安装

# NPM
npm install redux

# Yarn
yarn add redux

2. 创建

在 src文件夹下面创建一个store的文件夹,里面创建一个store.js

一、 单个redux

1. store.js

// 这里面的代码写在  store.js 中
// 1. 引入 redux 对应的函数
import { createStore }  from "redux"

// 创建一个初始的状态
const state={
    uname:"zrs"
}

// 任何修改的值得行为都会在这个函数中进行
// 第一个参数表示的之前的状态,第二个参数是 action 用来判断是哪个状态需要修改,就是dispatch函数传过来的对象
// 这个函数必须有一个返回值,返回值是状态对象
const reducer=(prevState=state,action)=>{
    // 这里负责处理修改状态
    // 将之前的状态 浅拷贝一份 ,操作浅拷贝的状态对象
    const newState={...prevState}
    
    switch(action.type){
        case "change-uname":
            newState.uname=action.payload
            return newState
        default:
            return prevState
    }
}
// 生成一个store
const store = createStore(reducer)

export {store}

2. 在组件中订阅

import {useState,useEffect} from "react"

import {store} from ".../store/index.js"

function  Home(){
    const [uname,setUname]=useState("")
    
   useEffect(() => {
       // 订阅
	let unsubscribe=store.subscribe(()=>{
        setUname(store.getState().uname)
		})
    
    return () => {
      // 删除订阅
      // 为什么需要删除订阅,因为组件在销毁和创建的时候,store是外来人,不会随着组件的删除和创建而删除和创建,就会导致重复的订阅,所以需要手动删除订阅
      unsubscribe();
    };  
  });
    
    return(
        <div>
            {uname}
        </div>
    )
}

3. 在组件中发dispatch修改状态

import {store}  from ".../store/index.js"

function  Center(){
    return(
        <div>
            <button onClick={()=>{
                    store.dispatch({
                        type:"change-uname",
                        payload:"zzr"
                    })
                }}>修改uname</button>
        <div/>
    )
}

二、redux 模块化

1. user模块

store 的文件夹下面,新建 userReducer.js

const userState={
    uname:"zrs"
}

const userReducer=(prevState=userState,action)=>{
    const newState={...prevState}
    
    switch(action.type){
        case "change-uname":
            newState.uname=action.payload
            return newState
        default:
            return prevState
    }
}

export {userReducer}

2. city 模块

store 的文件夹下面,新建 cityReducer.js

const cityState={
    cityName:"重庆"
}

const cityReducer=(prevState=cityState,action)=>{
    const newState={...prevState}
    
    switch(action.type){
        case "change-cityName":
            newState.cityName=action.payload
            return newState
        default:
            return prevState
    }
}

export {cityReducer}

3. 合并的部分

import  { createStore,combineReducers }  from "redux"

import { userReducer } from ".../userReducer.js"
import { cityReducer } from ".../cityReducer.js"

// combineReducer 用来合并 模块化的reducer
const rootReducer=combineReducer({
    userReducer,
    cityReducer
})

const store=createStore(rootReducer)

export {store}

4. 在组建中使用

import {useState,useEffect} from "react"

import {store} from ".../store/index.js"

function  Home(){
    const [uname,setUname]=useState("")
    
   useEffect(() => {
       // 订阅
	let unsubscribe=store.subscribe(()=>{
        // 模块化之后,就这里有了些改变 需要多添加 一个 模块的名称
        setUname(store.getState().userReducer.uname)
		})
    
    return () => {
      unsubscribe();
    }; 
  });
    return(
        <div>
            {uname}
        </div>
    ) 
}

5. 在组件中发 dispatch 修改状态

这里的操作与单个一样。

import {store}  from ".../store/index.js"

function  Center(){
    return(
        <div>
            <button onClick={()=>{
                    store.dispatch({
                        type:"change-uname",
                        payload:"zzr"
                    })
                }}>修改uname</button>
        <div/>
    )
}

三、redux-dispatch 执行异步

redux 中的异步操作需要在action中执行,那么也就是说,dispatch中不再是一个对象,而是一个函数。这个原生redux不能行,需要使用中间价 redux-thunk 或者 redux-promise

1. 安装对应的插件

npm i redux-thunk

2. 使用

// applyMiddleware() 用于加载中间件
import { applyMiddleware, combineReducers, createStore } from "redux";

import { userReducer } from ".../userReducer.js"
import { cityReducer } from ".../cityReducer.js"

// 引入 thunk 支持异步返回函数的方式
import reduxThunk from "redux-thunk";

// combineReducer 用来合并 模块化的reducer
const rootReducer=combineReducer({
    userReducer,
    cityReducer
})

// applyMiddleware函数的参数可以有多个,表示添加多个中间件
const store=createStore(rootReducer,applyMiddleware(reduxThunk))

export {store}

3. 在action中执行异步操作

在 store 文件夹下面创建一个 actions 文件夹,在这里创建一个 requestUname.js 文件。

function requestUname(uname,pwd){
    return (dispatch)=>{
        axios({
            method:"post",
            data:{
                uname,
                pwd
            }
        }).then(res=>{
			dispatch({
                type:"change-uname",
                payload:res.data.uname
            })
        })
    }
}

export {requestUname}

4. 在组件中使用

import {store}  from ".../store/index.js"

// 引入之前创建发送异步请求的函数
import {requestUname}  from ".../store/requestUname.js"

function  Center(){
    return(
        <div>
            <button onClick={()=>{
                    store.dispatch(requestUname(uname,pwd))
                }}>修改uname</button>
        <div/>
    )
}

四、redux 持久化存储

为什么需要持久化存储?

​ 因为数据是在内存中的,只要刷新页面,数据就会丢失或者重置,那么会影响用户体验或者其他操作,比如token,将数据持久化,可以保证数据不丢失,用户刷新页面,依旧是这些数据,体验很好。

持久化存储需要使用一个插件: redux-persist

1. 安装

npm i redux-persist

2. 在 store.js 中使用


import { applyMiddleware, combineReducers, createStore } from "redux";

import { userReducer } from ".../userReducer.js"
import { cityReducer } from ".../cityReducer.js"

// 持久化存储
import { persistStore, persistReducer } from "redux-persist";

// 默认使用localstorage 来持久化
import storage from "redux-persist/lib/storage";  

// 引入 thunk 支持异步返回函数的方式
import reduxThunk from "redux-thunk";

// 持久化的配置
const persistConfig = {
  key: "root",
  storage,
    // 白名单中的项,将会被持久化存储
  whitelist:['userReducer','cityReducer'] 
};

const rootReducer = combineReducers({
  userReducer,
  cityReducer,
});

// 第一个参数是按照什么样的规则持久化,第二个参数是合并之后 rootReducer
const persistedReducer = persistReducer(persistConfig, rootReducer);


const store = createStore(persistedReducer, applyMiddleware(reduxThunk));

let persistor = persistStore(store);

export { store, persistor };

3. 在项目入口的文件中需要配置一下

import React from "react";
import ReactDOM from "react-dom/client";
import App from "./App";

import { BrowserRouter as RouterSelf } from "react-router-dom";

import { PersistGate } from "redux-persist/integration/react";

// store 中导出另一个
import { persistor } from "./store/index";
const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(
  <RouterSelf>
    <PersistGate loading={null} persistor={persistor}>
      <App />
    </PersistGate>
  </RouterSelf>
);

4. 补充

这个持久化插件,有一个配置项,就是黑名单和白名单。

注意:黑名单和白名单中的值是子reducer的名字。

// 黑名单
const persistConfig = {
  key: 'root',
  storage: storage,
  blacklist: ['cityReducer'] // 黑名单中的项将不会被持久化
};
 
// 白名单
const persistConfig = {
  key: 'root',
  storage: storage,
  whitelist: ['userReducer'] // 仅仅只有白名单中的项会被持久化
};