【React】Redux的使用详解

文章目录

Redux的三大原则

单一数据源

​  整个应用程序的state被存储在一颗object tree中,并且这个object tree只存储在一个 store 中:

​  Redux并没有强制让我们不能创建多个Store,但是那样做并不利于数据的维护;

​  单一的数据源可以让整个应用程序的state变得方便维护、追踪、修改;

State是只读的

​  唯一修改State的方法一定是触发action,不要试图在其他地方通过任何的方式来修改State:

​  这样就确保了View或网络请求都不能直接修改state,它们只能通过action来描述自己想要如何修改state;

​  这样可以保证所有的修改都被集中化处理,并且按照严格的顺序来执行,所以不需要担心race condition(竟态)的问题;

使用纯函数来执行修改

​  通过reducer将 旧state和 actions联系在一起,并且返回一个新的State:

​  随着应用程序的复杂度增加,我们可以将reducer拆分成多个小的reducers,分别操作不同state tree的一部分;

​  但是所有的reducer都应该是纯函数,不能产生任何的副作用;

Redux官方图

react-redux使用

◼ 安装react-redux:

yarn add react-redux

 1、创建store管理全局状态

-src

---store

------- constants.js

先创建要使用的type常量

js 复制代码
export const ADD_NUMBER = "add_number"
export const SUB_NUMBER = "sub_number"

export const CHANGE_BANNERS = "change_banners"
export const CHANGE_RECOMMENDS = "change_recommends"

-src

---store

------- reducer.js

再创建reducer管理状态

js 复制代码
import * as actionTypes from "./constants"

const initialState = {
  counter: 100,
  
  banners: [],
  recommends: []
}

function reducer(state = initialState, action) {
  switch (action.type) {
    case actionTypes.ADD_NUMBER:
      return { ...state, counter: state.counter + action.num }
    case actionTypes.SUB_NUMBER:
      return { ...state, counter: state.counter - action.num }
    case actionTypes.CHANGE_BANNERS:
      return { ...state, banners: action.banners }
    case actionTypes.CHANGE_RECOMMENDS:
      return { ...state, recommends: action.recommends }
    default:
      return state
  }
}

export default reducer

-src

---store

------- index.js

在index导出整个store

js 复制代码
import { createStore } from "redux"
import reducer from "./reducer"


const store = createStore(reducer)

export default store

-src

---store

------- actionCreators.js

创建actionCreators,放修改状态的函数

js 复制代码
import * as actionTypes from "./constants"
import axios from "axios"

export const addNumberAction = (num) => ({
  type: actionTypes.ADD_NUMBER,
  num
})

export const subNumberAction = (num) => ({
  type: actionTypes.SUB_NUMBER,
  num
})


export const changeBannersAction = (banners) => ({
  type: actionTypes.CHANGE_BANNERS,
  banners
})

export const changeRecommendsAction = (recommends) => ({
  type: actionTypes.CHANGE_RECOMMENDS,
  recommends
})



export const fetchHomeMultidataAction = () => {
  // 如果是一个普通的action, 那么我们这里需要返回action对象
  // 问题: 对象中是不能直接拿到从服务器请求的异步数据的
  // return {}

  return function(dispatch, getState) {
    // 异步操作: 网络请求
    // console.log("foo function execution-----", getState().counter)
    axios.get("http://123.207.32.32:8000/home/multidata").then(res => {
      const banners = res.data.data.banner.list
      const recommends = res.data.data.recommend.list

      // dispatch({ type: actionTypes.CHANGE_BANNERS, banners })
      // dispatch({ type: actionTypes.CHANGE_RECOMMENDS, recommends })
      dispatch(changeBannersAction(banners))
      dispatch(changeRecommendsAction(recommends))
    })
  }

  // 如果返回的是一个函数, 那么redux是不支持的
  // return foo
}

​ 2、在项目index.js根节点引用

-src

--- index.js

 3、 在需要使用redux的页面或者组件中,通过connect高阶组件映射到该组件的props中

​ 解耦store和class组件的耦合

redux中异步操作

redux也引入了中间件(Middleware)的概念:

​  这个中间件的目的是在dispatch的action和最终达到的reducer之间,扩展一些自己的代码;

​  比如日志记录、调用异步接口、添加代码调试功能等等;

我们现在要做的事情就是发送异步的网络请求,所以我们可以添加对应的中间件:

​  这里官网推荐的、包括演示的网络请求的中间件是使用 redux-thunk

redux-thunk是如何做到让我们可以发送异步的请求呢?

​  我们知道,默认情况下的dispatch(action),action需要是一个JavaScript的对象;

​  redux-thunk可以让dispatch(action函数),action可以是一个函数;

​  该函数会被调用,并且会传给这个函数一个dispatch函数和getState函数;

​ ✓ dispatch函数用于我们之后再次派发action;

​ ✓ getState函数考虑到我们之后的一些操作需要依赖原来的状态,用于让我们可以获取之前的一些状态;

如何使用redux-thunk

1.安装redux-thunk

如何使用redux-thunk

yarn add redux-thunk

2.在创建store时传入应用了middleware的enhance函数

​  通过applyMiddleware来结合多个Middleware, 返回一个enhancer;

​  将enhancer作为第二个参数传入到createStore中;

js 复制代码
// 通过applyMiddleware来结合多个Middleware, 返回一个enhancer
const enhancer = applyMiddleware(thunkMiddleware);
// 将enhancer作为第二个参数传入到createStore中
const store = createStore(reducer, enhancer);

3.定义返回一个函数的action:

​  注意:这里不是返回一个对象了,而是一个函数;

​  该函数在dispatch之后会被执行;

js 复制代码
const getHomeMultidataAction = () => {
  return (dispatch) => {
    axios.get("http://123.207.32.32:8000/home/multidata").then(res => {
      const data = res.data.data;
      dispatch(changeBannersAction(data.banner.list));
      dispatch(changeRecommendsAction(data.recommend.list));
    })
  }
}

combineReducers函数

事实上,redux给我们提供了一个combineReducers函数可以方便的让我们对多个reducer进行合并:

那么combineReducers是如何实现的呢?

​  事实上,它也是将我们传入的reducers合并到一个对象中,最终返回一个combination的函数(相当于我们之前的reducer函

数了);

​  在执行combination函数的过程中,它会通过判断前后返回的数据是否相同来决定返回之前的state还是新的state;

​  新的state会触发订阅者发生对应的刷新,而旧的state可以有效的组织订阅者发生刷新;

相关推荐
清云随笔19 分钟前
axios 实现 无感刷新方案
前端
鑫宝Code20 分钟前
【React】状态管理之Redux
前端·react.js·前端框架
忠实米线28 分钟前
使用pdf-lib.js实现pdf添加自定义水印功能
前端·javascript·pdf
pink大呲花31 分钟前
关于番外篇-CSS3新增特性
前端·css·css3
少年维持着烦恼.35 分钟前
第八章习题
前端·css·html
我是哈哈hh38 分钟前
HTML5和CSS3的进阶_HTML5和CSS3的新增特性
开发语言·前端·css·html·css3·html5·web
田本初1 小时前
如何修改npm包
前端·npm·node.js
明辉光焱1 小时前
[Electron]总结:如何创建Electron+Element Plus的项目
前端·javascript·electron
牧码岛2 小时前
Web前端之汉字排序、sort与localeCompare的介绍、编码顺序与字典顺序的区别
前端·javascript·web·web前端