Redux详解(一)

1. Redux的作用

React是在视图层帮助我们解决了DOM的渲染过程,但是State依然是留给我们自己来管理:
  • 无论是组件定义自己的state,还是组件之间的通信通过props进行传递;也包括通过Context进行数据之间的共享;
  • React主要负责帮助我们管理视图,state如何维护最终还是我们自己来决定;
Redux就是帮助react管理state的容器Redux是 JavaScript的状态容器 ,提供了 可预测的状态管理;
Redux是一个独立的npm库,并不只能适用于React,也可以与其他javaScript构建界面库使用,具有较高的灵活性,且小体积的特点;

2. Redux核心理念 - Store

对于多个页面共享的一个数据时,需要定义统一的规范来操作数据,才能使整个数据的变化可追踪;

3. Redux核心理念 - action

Redux要求我们通过action来更新数据:
  • 所有数据的变化,必须通过派发(dispatch)action来更新;
  • action是一个普通的JavaScript对象 ,用来描述这次 更新的type和content;
Redux详解(一)_第1张图片
  • 强制使用action的好处是可以清晰的知道数据到底发生了什么样的变化,所有的数据变化都是可跟追、可预测的;
  • actions可以派发的是对象或者函数

4. Redux核心理念 - reducer

通过actions派发修改state状态的桥梁,就是reducer

  • reducer是一个纯函数;
  • reducer做的事情就是 将传入的state和action结合起来生成一个新的state;
import * as actionsTypes from './constant'

const initialState = {
  counter: 10
}

function reducer(state = initialState, actions) {
  switch(actions.type) {
    case actionsTypes.ADD_NUMBER: 
      return {...state, counter: state.counter + actions.num}
    case actionsTypes.SUB_NUMBER: 
      return {...state, counter: state.counter - actions.num}
    default:
      return state
  }
}

export default reducer

5. 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都应该是纯函数 ,不能产生任何的副作用;

6. Redux使用过程

1. 建一个对象,作为我们要保存的状态;

2. 创建Store来存储这个state;

  • 创建store时必须创建reducer;
  • 可以通过 store.getState 来获取当前的state;
3.  过action来修改state;
  • 通过dispatch来派发action;
  • 通常action中都会有type属性,也可以携带其他的数据;
4.  改reducer中的处理代码;
  • reducer是一个纯函数,不需要直接修改state;

5. Redux结构划分;

将所有的逻辑代码写到一起,那么当redux变得复杂时代码就难以维护。
分为以下几个文件模块
Redux详解(一)_第2张图片

constant.js 定义type的常量

export const ADD_NUMBER = "add_number"
export const SUB_NUMBER = "sub_number"

createActions.js dispatch派发的actions, 返回一个对象

import * as actionsType from './constant'

export const addNumberActions = (num) => ({
  type: actionsType.ADD_NUMBER,
  num
})

export const subNumberActions = (num) => ({
  type: actionsType.SUB_NUMBER,
  num
})

reducer.js 处理派发的actions,返回新的state 实现state状态更新

import * as actionsTypes from './constant'

const initialState = {
  counter: 10
}

function reducer(state = initialState, actions) {
  switch(actions.type) {
    case actionsTypes.ADD_NUMBER: 
      return {...state, counter: state.counter + actions.num}
    case actionsTypes.SUB_NUMBER: 
      return {...state, counter: state.counter - actions.num}
    default:
      return state
  }
}

export default reducer

index.js 导出reducer 

import reducer from "./reducer";

export default reducer
export * from "./createActions"

创建store

import { createStore, applyMiddleware, compose, combineReducers } from 'redux'
import thunk from 'redux-thunk'

import counterReducer from './features/counter'
import homeReducer from './features/home'
import userInfoReducer from './features/userInfo'

const reducer = combineReducers({
  counter: counterReducer,
  home: homeReducer,
  userInfo: userInfoReducer
})

// 打开 redux-devtools  {trace: true} 追踪代码执行
const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__({trace: true}) || compose;

const store = createStore(reducer, composeEnhancers(applyMiddleware(thunk)))

export default store

7. Redux使用流程

注意:此图出自coderwhy老师的react课程讲解,有兴趣的小伙伴可以腾讯课堂搜索why老师课程学习

Redux详解(一)_第3张图片

Redux官方文档对于Redux更新state的流程图表述:

Redux详解(一)_第4张图片

8. Redux融入react使用

以counter数加减实现来说
核心代码主要是两个:
  • 在 componentDidMount 中定义数据的变化,当数据发生变化时重新设置 counter;
  • 在发生点击事件时,调用store的dispatch来派发对应的action;
8.1 react-redux使用

前文开头强调redux和react没有直接的关系,在React, Angular, Ember, jQuery, or vanilla JavaScript也完全可以使用Redux。

React官方为了在项目中更高效的使用redux,redux官方提供了react-redux库

npm install react-redux

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


const root = ReactDOM.createRoot(document.querySelector("#root"))
root.render(
  
    
  
  )

组件中:

import React, { PureComponent } from 'react'
import { connect } from 'react-redux'
import { addNumberActions, subNumberActions } from '../../store/features/counter'

export class About extends PureComponent {

  calcNumber(num, isAdd) {
    if(isAdd) {
      this.props.addNumber(num)
    } else {
      this.props.subNumber(num)
    }
  }

  render() {
    const { counter, banners, recommends } = this.props

    return (
      

About: counter: {counter}

banners数据:

    { banners.map((item, index) => { return
  • {item.title}
  • }) }

recommends数据:

    { recommends.map((item, index) => { return
  • {item.title}
  • }) }
) } } const mapStateToProps = (state) => ({ counter: state.counter.counter, banners: state.home.banners, recommends: state.home.recommends }) const mapDispatchToProps = (dispatch) => ({ addNumber(num) { dispatch(addNumberActions(num)) }, subNumber(num) { dispatch(subNumberActions(num)) } }) export default connect(mapStateToProps, mapDispatchToProps)(About)
8.2 组件中的异步操作

对于网络请求中的数据,需要交给redux来处理,需要通过中间件(middleware)来实现

理解中间件:

  • 中间件的目的是在dispatch的action和最终达到的reducer之间,扩展一些自己的代码;
  • 比如 日志记录、调用异步接口、添加代码调试功能 等等;
对于发送异步的网络请求,通过 官网推荐的、包括演示的网络请求的中间件是使用 redux-thunk
  • 默认情况下的dispatch(action),action需要是一个JavaScript的对象;
  • redux-thunk可以让dispatch(action函数),action可以是一个函数;
  • 该函数会被调用,并且会传给 这个函数一个 dispatch函数和getState函数
    • dispatch函数 用于我们之后再次派发action;
    • getState函数 考虑到我们之后的一些操作需要依赖原来的状态,用于让我们可以获取之前的一些状态;

npm install redux-thunk

const store = createStore(reducer, applyMiddleware(thunk))
export const fetchHomeMultidataActions = () => {
  return (dispatch, getData) => {
    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(changeBannersActions(banners))
      dispatch(changeRecommendsActions(recommends))
    })
  }
}
8.3 store的模块化分
目前我们合并的方式是通过每次调用reducer函数自己来返回一个新的对象,事实上,redux给我们提供了一个 combineReducers函数 可以方便的让我们对多个reducer进行合并:
import { createStore, applyMiddleware, compose, combineReducers } from 'redux'

const reducer = combineReducers({
  counter: counterReducer,
  home: homeReducer,
  userInfo: userInfoReducer
})
combineReducers实现原理
  • 将我们传入的reducers合并到一个对象中,最终返回一个combination的函数(相当于我们之前的reducer函数了);
  • 在执行combination函数的过程中,它会通过判断前后返回的数据是否相同来决定返回之前的state还是新的state;
  • 新的state会触发订阅者发生对应的刷新,而旧的state可以有效的组织订阅者发生刷新;​​​​​​​

你可能感兴趣的:(React学习记录,前端,javascript,开发语言)