关于前端:一文总结reduxreactreduxreduxsaga

6次阅读

共计 25091 个字符,预计需要花费 63 分钟才能阅读完成。

redux、react-redux、redux-saga 总结

前言

hello 大家好,我是风不识途,最近始终在整顿 redux 系列文章,发现对于初学者不太敌对,关系盘根错节,难倒是不太难,就是比较复杂 (其实写比拟少),所以这篇带你全面理解redux、react-redux、redux-thunk 还有redux-sage,immutable(多图预警),因为知识点比拟多,倡议先珍藏(珍藏等于学会了),对你有帮忙的话就给个赞👍

意识纯函数

JavaScript 纯函数

  • 函数式编程 中有一个概念叫 纯函数 , JavaScript 合乎函数式编程的范式, 所以也有纯函数的概念
  • React 中,纯函数的概念十分重要 ,在接下来咱们学习的Redux 中也十分重要,所以咱们必须来回顾一下纯函数
  • 纯函数的定义简略总结一下:

    • 纯函数指的是, 每次给雷同的参数, 肯定返回雷同的后果
    • 函数在执行过程中, 不能产生副作用
  • 纯函数 (Pure Function ) 的注意事项:

    • 在纯函数中不能应用随机数
    • 不能应用以后的工夫或日期, 因为后果是会变的
    • 不能应用或者批改全局状态, 比方 DOM, 文件、数据库等等(因为如果全局状态扭转了, 它就会影响函数的后果)
    • 纯函数中的参数不能变动, 否则函数的后果就会扭转

React 中的纯函数

  • 为什么纯函数在函数式编程中十分重要呢?

    • 因为你能够安心的写和安心的用
    • 你在写的时候保障了函数的纯度,实现本人的业务逻辑即可,不须要关怀传入的内容或者函数体依赖了内部的变量
    • 你在用的时候,你确定你的输出内容不会被任意篡改,并且本人确定的输出,肯定会有确定的输入
  • React 非常灵活, 但它也有一个严格的规定:

    • 所有 React 组件都必须像 ” 纯函数 ” 一样爱护它们的 ”props” 不被更改

意识 Redux

为什么须要 redux

  • JavaScript开发的应用程序, 曾经变得 非常复杂 了:

    • JavaScript须要治理的状态越来越多, 越来越简单了
    • 这些状态包含服务器返回的数据, 用户操作的数据等等, 也包含一些 UI 的状态
  • 治理一直变动的 state 是十分艰难的:

    • 状态之间互相存在依赖 , 一个状态的变动会引起另一个状态的变动, View 页面也有可能会引起状态的变动
    • 当程序简单时, state在什么时候, 因为什么起因产生了变动, 产生了怎么的变动, 会变得十分难以管制和追踪

React 的作用

  • React只是在视图层帮忙咱们解决了 DOM 的渲染过程, 然而 state 仍然是留给咱们本人来治理:

    • 无论是组件定义本人的 state,还是组件之间的通信通过props 进行传递
    • 也包含通过 Context 进行数据之间的共享
    • React次要负责帮忙咱们治理视图,state如何保护最终还是咱们本人来决定

  • Redux就是一个帮忙咱们治理 State 的容器:

    • ReduxJavaScript 的状态容器, 提供了可预测的状态治理
  • Redux除了和 React 一起应用之外, 它也能够和其余界面库一起来应用(比方Vue), 并且它十分小 (包含依赖在内,只有 2kb)

Redux 的核心理念 -Store

  • Redux的核心理念非常简单
  • 比方咱们有一个敌人列表须要治理:

    • 如果咱们没有定义对立的标准来操作这段数据,那么整个数据的变动就是无奈跟踪的
    • 比方页面的某处通过 products.push 的形式减少了一条数据
    • 比方另一个页面通过 products[0].age = 25 批改了一条数据
  • 整个应用程序盘根错节,当呈现 bug 时,很难跟踪到底哪里产生的变动

Redux 的核心理念 -action

  • Redux要求咱们通过 action 来更新state

    • 所有数据的变动, 必须通过 dispatch 来派发 action 来更新
    • action是一个一般的 JavaScript 对象,用来形容这次更新的 typecontent
  • 比方上面就是几个更新 friendsaction:

    • 强制应用 action 的益处是能够清晰的晓得数据到底产生了什么样的变动,所有的数据变动都是可跟追踪、可预测的
    • 当然,目前咱们的 action 是固定的对象,实在利用中,咱们会通过函数来定义,返回一个action

Redux 的核心理念 -reducer

  • 然而如何将 stateaction分割在一起呢? 答案就是reducer

    • reducer是一个纯函数
    • reducer做的事件就是将传入的 stateaction联合起来来生成一个新的state

Redux 的三大准则

  • 繁多数据源

    • 整个应用程序的 state 被存储在一颗 object tree 中, 并且这个 object tree 只存储在一个store
    • Redux并没有强制让咱们不能创立多个Store,然而那样做并不利于数据的保护
    • 繁多的数据源能够让整个应用程序的 state 变得不便保护、追踪、批改
  • State 是只读的

    • 惟一批改 state 的办法肯定是触发action, 不要试图在其它的中央通过任何的形式来批改state
    • 这样就确保了 View 或网络申请都不能间接批改 state,它们只能通过action 来形容本人想要如何批改state
    • 这样能够保障所有的批改都被集中化解决,并且依照严格的程序来执行,所以不须要放心 race condition(竟态) 的问题
  • 应用纯函数来执行批改

    • 通过 reducer 将旧 stateaction 分割在一起, 并且返回一个新的state
    • 随着应用程序的复杂度减少,咱们能够将 reducer 拆分成多个小的 reducers,别离操作不同state tree 的一部分
    • 然而所有的 reducer 都应该是纯函数,不能产生任何的副作用

Redux 的根本应用

Redux 中外围的 API

redux的装置: yarn add redux

  1. createStore 能够用来创立 store对象
  2. store.dispatch 用来派发 action , action 会传递给 store
  3. reducer接管 action,reducer 计算出新的状态并返回它 (store负责调用reducer)
  4. store.getState 这个办法能够帮忙获取 store 里边所有的数据内容
  5. store.subscribe办法能够让让咱们订阅 store 的扭转,只有 store 产生扭转,store.subscribe 这个 函数接管的这个回调函数 就会被执行

小结

  1. 创立sotore, 决定 store 要保留什么状态
  2. 创立action, 用户在程序中实现什么操作
  3. 创立reducer, reducer 接管 action 并返回更新的状态

Redux 的应用过程

  1. 创立一个对象, 作为咱们要保留的状态
  2. 创立 Store 来存储这个state

    • 创立 store 时必须创立reducer
    • 咱们能够通过 store.getState 来获取以后的state
  3. 通过 action 来批改state

    • 通过 dispatch 来派发action
    • 通常 action 中都会有 type 属性,也能够携带其余的数据
  4. 批改 reducer 中的解决代码

    • 这里肯定要记住,reducer是一个 纯函数,不能间接批改state
    • 前面会讲到间接批改 state 带来的问题
  5. 能够在派发 action 之前,监听 store 的变动
import {createStore} from 'redux'

// 1. 初始化 state
const initState = {counter: 0}

// 2.reducer 纯函数 不能批改传递的 state
function reducer(state = initState, action) {switch (action.type) {
    case 'INCREMENT':
      return {...state, counter: state.counter + 1}
    case 'ADD_COUNTER':
      return {...state, counter: state.counter + action.num}
    default:
      return state
  }
}

// 3.store 参数放一个 reducer
const store = createStore(reducer)

// 4.action
const action1 = {type: 'INCREMENT'}
const action2 = {type: 'ADD_COUNTER', num: 2}

// 5. 订阅 store 的批改
store.subscribe(() => {console.log('state 产生了扭转:', store.getState().counter)
})

// 6. 派发 action
store.dispatch(action1)
store.dispatch(action2)

Redux 构造划分

  • 如果咱们将所有的逻辑代码写到一起, 那么当 redux 变得复杂时代码就难以保护
  • 对代码进行拆分, 将 store、reducer、action、constants 拆分成一个个文件

<details>
<summary> 拆分目录 </summary>

</details>

Redux 应用流程

Redux 官网流程图

React-Redux 的应用

redux 融入 react 代码(案例)

  • redux融入 react 代码案例:

    • Home组件:其中会展现以后的 counter 值,并且有一个 + 1 和 + 5 的按钮
    • Profile组件:其中会展现以后的 counter 值,并且有一个 - 1 和 - 5 的按钮

  • 外围代码次要是两个:

    • componentDidMount 中订阅数据的变动,当数据发生变化时从新设置 counter
    • 在产生点击事件时,调用 storedispatch来派发对应的action

自定义 connect 函数

当咱们多个组件应用 redux 时, 反复的代码太多了, 比方: 订阅 state 勾销订阅 state 或 派发action 获取state

将反复的代码进行封装, 将不同的 statedispatch作为参数进行传递

//  connect.js 
import React, {PureComponent} from 'react'
import {StoreContext} from './context'
/**
 * 1. 调用该函数: 返回一个高阶组件
 *      传递须要依赖 state 和 dispatch 来应用 state 或通过 dispatch 来扭转 state
 *
 * 2. 调用高阶组件:
 *      传递该组件须要依赖 store 的组件
 *
 * 3. 次要作用:
 *      将反复的代码抽取到高阶组件中, 并将该组件依赖的 state 和 dispatch
 *      通过调用 mapStateToProps()或 mapDispatchToProps()函数
 *      并将该组件依赖的 state 和 dispatch 供该组件应用, 其余应用 store 的组件不用依赖 store
 *
 * 4.connect.js: 优化依赖
 *      目标: 然而下面的 connect 函数有一个很大的缺点:依赖导入的 store
 *      优化: 正确的做法是咱们提供一个 Provider,Provider 来自于咱们
 *             Context,让用户将 store 传入到 value 中即可;*/
export function connect(mapStateToProps, mapDispatchToProps) {return function enhanceComponent(WrapperComponent) {
    class EnhanceComponent extends PureComponent {constructor(props, context) {super(props, context)

        // 组件依赖的 state
        this.state = {storeState: mapStateToProps(context.getState()),
        }
      }

      // 订阅数据发生变化, 调用 setState 从新 render
      componentDidMount() {this.unsubscribe = this.context.subscribe(() => {
          this.setState({centerStore: mapStateToProps(this.context.getState()),
          })
        })
      }

      // 组件被卸载勾销订阅
      componentWillUnmount() {this.unsubscribe()
      }

      render() {// 上面的 WrapperComponent 相当于 home 组件(就是你传递的组件)
        // 你须要将该组件须要依赖的 state 和 dispatch 作为 props 进行传递
        return (
          <WrapperComponent
            {...this.props}
            {...mapStateToProps(this.context.getState())}
            {...mapDispatchToProps(this.context.dispatch)}
          />
        )
      }
    }
    // 取出 Provider 提供的 value
    EnhanceComponent.contextType = StoreContext
    return EnhanceComponent
  }
}

// home.js
// 定义组件依赖的 state 和 dispatch
const mapStateToProps = state => ({counter: state.counter,})

const mapDispatchToProps = dispatch => ({increment() {dispatch(increment())
  },
  addNumber(num) {dispatch(addAction(num))
  },
})
export default connect(mapStateToProps,mapDispatchToProps)(依赖 redux 的组件)

react-redux 应用

  • 开始之前须要强调一下,reduxreact 没有间接的关系,你齐全能够在 React, Angular, Ember, jQuery, or vanilla JavaScript 中应用 Redux
  • 只管这样说,redux 仍然是和 React 或者 Deku 的库联合的更好,因为他们是通过 state 函数来形容界面的状态,Redux 能够发射状态的更新,让他们作出相应。
  • 尽管咱们之前曾经实现了 connectProvider 这些帮忙咱们实现连贯 redux、react 的辅助工具,然而实际上redux 官网帮忙咱们提供了 react-redux 的库,能够间接在我的项目中应用,并且实现的逻辑会更加的谨严和高效
  • 装置react-redux

    • yarn add react-redux
// 1.index.js
import {Provider} from 'react-redux'
ReactDOM.render(<Provider store={store}>
    <App />
  </Provider>,
  document.getElementById('root')
)

// 2.home.js
import {connect} from 'react-redux'
// 定义须要依赖的 state 和 dispatch (函数须要返回一个对象)
export default connect(mapStateToProps, mapDispatchToProps)(About)

react-redux 源码导读

Redux-Middleware 中间件

组件中异步操作

  • 在之前简略的案例中,redux中保留的 counter 是一个本地定义的数据

    • 咱们能够间接通过同步的操作来 dispatch actionstate 就会被立刻更新。
    • 然而实在开发中,redux中保留的 很多数据可能来自服务器 ,咱们须要进行 异步的申请 ,再将数据保留到redux
  • 网络申请能够在 class 组件的 componentDidMount 中发送,所以咱们能够有这样的构造:

redux 中异步操作

  • 下面的代码有一个缺点:

    • 咱们必须将 网络申请 的异步代码放到组件的生命周期中来实现
  • 为什么将网络申请的异步代码放在 redux 中进行治理?

    • 前期代码量的减少,如果把网络申请异步函数放在组件的生命周期里,这个生命周期函数会变得越来越简单,组件就会变得越来越大
    • 事实上,网络申请到的数据也属于状态治理的一部分 ,更好的一种形式应该是将其也交给redux 来治理

  • 然而在 redux 中如何能够进行异步的操作呢?

    • 应用中间件 (Middleware)
    • 学习过 ExpressKoa框架的童鞋对中间件的概念肯定不生疏
    • 在这类框架中,Middleware能够帮忙咱们在 申请和响应之间嵌入一些操作的代码,比方 cookie 解析、日志记录、文件压缩等操作

了解中间件(重点)

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

    • 这个 <font color=’red’> 中间件的目标是在 dispatchaction和最终达到的 reducer 之间,扩大一些本人的代码 </font>
    • 比方日志记录、调用异步接口、增加代码调试性能等等

  • redux-thunk是如何做到让咱们能够发送异步的申请呢?

    • 默认状况下的 dispatch(action)action 须要是一个 JavaScript 的对象
    • redux-thunk能够让 dispatch(action 函数), action<font color=’red’>能够是一个函数</font>
    • 该函数会被调用, 并且会传给这个函数两个参数: 一个 dispatch 函数和 getState 函数

      • dispatch函数用于咱们之后再次派发action
      • getState函数思考到咱们之后的一些操作须要依赖原来的状态,用于让咱们能够获取之前的一些状态

redux-thunk 的应用

  1. 装置redux-thunk

    • yarn add redux-thunk
  2. 在创立 store 时传入利用了 middlewareenhance函数

    • 通过 applyMiddleware 来联合多个Middleware, 返回一个enhancer
    • enhancer 作为第二个参数传入到 createStore

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

    • 留神:这里不是返回一个对象了,而是一个 函数
    • 该函数在 dispatch 之后会被执行

<details>
<summary>查看代码</summary>
<pre>import {createStore, applyMiddleware} from 'redux'
import reducer from './reducer'
import thunk from 'redux-thunk'<br/>
const store = createStore(
reducer,
applyMiddleware(thunk) // applyMiddleware 能够应用中间件模块
)
export default store
</pre></details>

redux-devtools

redux-devtools 插件

  • 咱们之前讲过,redux能够不便的让咱们对状态进行跟踪和调试,那么如何做到呢?

    • redux官网为咱们提供了 redux-devtools 的工具
    • 利用这个工具,咱们能够晓得每次状态是如何被批改的,批改前后的状态变动等等
  • 应用步骤:

    • 第一步:在浏览器上装置 redux-devtools 扩大插件
    • 第二步:在 redux 中集成 devtools 的中间件
// store.js 开启 redux-devtools 扩大
import {createStore, applyMiddleware, compose} from 'redux'

// composeEnhancers 函数
const composeEnhancers =
  window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__({trace: true}) || compose

// 通过 applyMiddleware 来联合多个 Middleware, 返回一个 enhancer
const enhancer = applyMiddleware(thankMiddleware)

// 通过 enhancer 作为第二个参数传递 createStore 中
const store = createStore(reducer, composeEnhancers(enhancer))

export default store

redux-sage

generator

Generator 函数是 ES6 提供的一种异步编程解决方案,语法行为与传统函数齐全不同

Generator 函数有多种了解角度。语法上,首先能够把它了解成,Generator 函数是一个状态机,封装了多个外部状态。

// 生成器函数的定义
// 默认返回: Generator
function* foo() {console.log('111')
  yield 'hello'
  console.log('222')
  yield 'world'
  console.log('333')
  yield 'jane'
  console.log('444')
}
// iterator: 迭代器
const result = foo()
console.log(result)

// 应用迭代器
// 调用 next, 就会耗费一次迭代器
const res1 = result.next()
console.log(res1) // {value: "hello", done: false}
const res2 = result.next()
console.log(res2) // {value: "world", done: false}
const res3 = result.next()
console.log(res3) // {value: "jane", done: false}
const res4 = result.next()
console.log(res4) // {value: undefined, done: true}

redux-sage 流程

redux-saga 的应用

  • redux-saga是另一个比拟罕用在 redux 发送异步申请的中间件, 它的应用更加的灵便
  • Redux-saga的应用步骤如下

    1. 装置redux-sage: yarn add redux-saga
    2. 集成 redux-saga 中间件

      • 引入 createSagaMiddleware 后, 须要创立一个 sagaMiddleware
      • 而后通过 applyMiddleware 应用这个中间件,接着创立 saga.js 这个文件
      • 启动中间件的监听过程, 并且传入要监听的saga
    3. saga.js文件的编写

      • takeEvery: 能够传入多个监听的actionType, 每一个都能够被执行(对应有一个takeLatest, 会勾销后面的)
      • put: 在 saga 中派发 action 不再是通过dispatch, 而是通过put
      • all: 能够在 yield 的时候 put 多个action
// store.js
import createSageMiddleware from 'redux-saga'
import saga from './saga'
// 1. 创立 sageMiddleware 中间件
const sagaMiddleware = createSageMiddleware()
// 2. 利用一些中间件
const enhancer = applyMiddleware(sagaMiddleware)
const store = createStore(reducer,composeEnhancers(enhancer))

sagaMiddleware.run(saga)
export default store

// saga.js
import {takeEvery, put, all} from 'redux-saga/effects'
import {FETCH_HOME_DATA} from './constant'

function* fetchHomeData(action) {const res = yield axios.get('http://123.207.32.32:8000/home/multidata')
  const banners = res.data.data.banner.list
  const recommends = res.data.data.recommend.list
  // dispatch action 提交 action,redux-sage 提供了 put
  yield all([yield put(changeBannersAction(banners)),
    yield put(changeRecommendAction(recommends)),
  ])
}

function* mySaga() {
  // 参数一: 要拦挡的 actionType
  // 参数二: 生成器函数
  yield all([takeEvery(FETCH_HOME_DATA, fetchHomeData),
  ])
}

export default mySaga

reducer 代码拆分

Reducer 代码拆分

  • 咱们来看一下目前咱们的reducer

    • 以后这个 reducer 既有解决 counter 的代码,又有解决 home 页面的数据
    • 后续 counter 相干的状态或 home 相干的状态会进一步变得更加简单
    • 咱们也会持续增加其余的相干状态,比方购物车、分类、歌单等等
    • 如果将所有的状态都放到一个 reducer 中进行治理,随着我的项目的日趋宏大,必然会造成代码臃肿、难以保护
  • 因而, 咱们能够对 reducer 进行拆分:

    • 咱们先抽取一个对 counter 解决的reducer
    • 再抽取一个对 home 解决的reducer
    • 将它们合并起来

Reducer 文件拆分

  • 目前咱们曾经将不同的状态解决拆分到不同的 reducer 中,咱们来思考:

    • 尽管曾经放到不同的函数了,然而这些函数的解决仍然是在同一个文件中,代码十分的凌乱
    • 另外对于 reducer 中用到的 constantaction 等咱们也仍然是在同一个文件中;

combineReducers 函数

  • 目前咱们合并的形式是通过每次调用 reducer 函数本人来返回一个新的对象
  • 事实上,redux给咱们提供了一个 combineReducers 函数能够不便的让咱们对多个 reducer 进行合并
import {combineReducers} from 'redux'
import {reducer as counterReducer} from './count'
import {reducer as homeReducer} from './home'

export const reducer = combineReducers({
  counterInfo: counterReducer,
  homeInfo: homeReducer,
})
  • 那么 combineReducers 是如何实现的呢?

    • 它将咱们传递的 reducer 合并成一个对象, 最终返回一个 combination 函数
    • 在执行 combination 函数过程中, 会通过判断前后返回的数据是否雷同来决定返回之前的 state 还是新的state

immutableJs

数据可变形的问题

  • React 开发中,咱们总是会强调数据的不可变性:

    • 无论是类组件中的 state,还是reduex 中治理的state
    • 事实上在整个 JavaScript 编码的过程中,数据的不可变性都是十分重要的
  • 数据的可变性引发的问题(案例):

    • 咱们明明没有批改 obj,只是批改了 obj2,然而最终 obj 也被咱们批改掉了
    • 起因非常简单,对象是援用类型,它们指向同一块内存空间,两个援用都能够任意批改
const obj1 = {name: 'jane', age: 18}
const obj2 = obj1
obj1.name = 'kobe'
console.log(obj2.name) // kobe
  • 有没有方法解决下面的问题呢?

    • 进行对象的拷贝即可:Object.assign或扩大运算符
  • 这种对象的浅拷贝有没有问题呢?

    • 从代码的角度来说,没有问题,也解决了咱们理论开发中一些潜在危险
    • 从性能的角度来说,有问题,如果对象过于宏大,这种拷贝的形式会带来性能问题以及内存节约
  • 有人会说,开发中不都是这样做的吗?

    • 从来如此,便是对的吗?

意识 ImmutableJS

  • 为了解决下面的问题,呈现了 Immutable 对象的概念:

    • Immutable对象的特点是只有批改了对象,就会返回一个新的对象,旧的对象不会产生扭转;
  • 然而这样的形式就不会节约内存了吗?

    • 为了节约内存,又呈现了一个新的算法:Persistent Data Structure(长久化数据结构或一致性数据结构)
  • 当然,咱们一听到长久化第一反馈应该是数据被保留到本地或者数据库,然而这里并不是这个含意:

    • 用一种数据结构来保留数据
    • 当数据被批改时,会返回一个对象,然而 新的对象会尽可能的利用之前的数据结构而不会对内存造成节约,如何做到这一点呢?构造共享:

  • 装置Immutable: yarn add immutable

ImmutableJS 常见 API

留神:我这里只是演示了一些 API,更多的形式能够参考官网

作用:不会批改原有数据结构,返回一个批改后新的拷贝对象

  • JavaScripImutableJS 间接的转换

    • 对象转换成 Immutable 对象:Map
    • 数组转换成 Immtable 数组:List
    • 深层转换:fromJS
const im = Immutable
// 对象转换成 Immutable 对象
const info = {name: 'kobe', age: 18}
const infoIM = im.Map()

// 数组转换成 Immtable 数组
const names = ["abc", "cba", "nba"]
const namesIM = im.List(names)
  • ImmutableJS的基本操作:

    • 批改数据:set(property, newVal)

      • 返回值: 批改后新的数据结构
    • 获取数据:get(property/index)
    • 获取深层 Immutable 对象数据 (子属性也是Immutable 对象): getIn(['recommend', 'topBanners'])
// set 办法 不会批改 infoIM 原有数据结构,返回批改后新的数据结构
const newInfo2IM = infoIM.set('name', 'james')
const newNamesIM = namesIM.set(0, 'why')

// get 办法
console.log(infoIM.get('name'))// -> kobe
console.log(namesIM.get(0))// -> abc

联合 Redux 治理数据

  1. ImmutableJS重构redux

    • yarn add Immutable
    • yarn add redux-immutable
  2. 应用 redux-immutable 中的 combineReducers;
  3. 所有的 reducer 中的数据都转换成 Immutable 类型的数据

FAQ

React 中的 state 如何治理

  • 目前我的项目中采纳的 state 治理计划(参考即可):

    • 相干的组件外部能够保护的状态, 在组件外部本人来保护
    • 只有是须要共享的状态, 都交给 redux 来治理和保护
    • 从服务器申请的数据(包含申请的操作) , 交给 redux 来保护

前言

hello 大家好,我是风不识途,最近始终在整顿 redux 系列文章,发现对于初学者不太敌对,关系盘根错节,难倒是不太难,就是比较复杂 (其实写比拟少),所以这篇带你全面理解redux、react-redux、redux-thunk 还有redux-sage,immutable(多图预警),因为知识点比拟多,倡议先珍藏(珍藏等于学会了),对你有用的话就给个赞👍

意识纯函数

JavaScript 纯函数

  • 函数式编程 中有一个概念叫 纯函数 , JavaScript 合乎函数式编程的范式, 所以也有纯函数的概念

  • React 中,纯函数的概念十分重要 ,在接下来咱们学习的Redux 中也十分重要,所以咱们必须来回顾一下纯函数

  • 
    纯函数的维基百科定义(理解即可)
    
    ​
    
  • 纯函数的定义简略总结一下:

    
    *   纯函数指的是, 每次给雷同的参数, 肯定返回雷同的后果
        
    *   函数在执行过程中, 不能产生副作用
        
  • 
    ** 纯函数 (`Pure Function`) 的注意事项:**
    
    ​
    

React 中的纯函数

  • 为什么纯函数在函数式编程中十分重要呢?

    
    *   因为你能够安心的写和安心的用
        
    *   你在写的时候保障了函数的纯度,实现本人的业务逻辑即可,不须要关怀传入的内容或者函数体依赖了内部的变量
        
    *   你在用的时候,你确定你的输出内容不会被任意篡改,并且本人确定的输出,肯定会有确定的输入
        
  • React 非常灵活, 但它也有一个严格的规定:

    
    *   所有 React 组件都必须像 "纯函数" 一样爱护它们的 "props" 不被更改
        

意识 Redux

为什么须要 redux

  • JavaScript开发的应用程序, 曾经变得 非常复杂 了:

    
    *   `JavaScript`** 须要治理的状态越来越多 **, 越来越简单了
        
    *   这些状态包含服务器返回的数据, 用户操作的数据等等, 也包含一些 `UI` 的状态
        
  • 治理一直变动的 state 是十分艰难的:

    
    *   ** 状态之间互相存在依赖 **, 一个状态的变动会引起另一个状态的变动, `View` 页面也有可能会引起状态的变动
        
    *   当程序简单时, `state` 在什么时候, 因为什么起因产生了变动, 产生了怎么的变动, 会变得十分难以管制和追踪
        

React 的作用

  • React只是在视图层帮忙咱们解决了 DOM 的渲染过程, 然而 state 仍然是留给咱们本人来治理:

    
    *   无论是组件定义本人的 `state`,还是组件之间的通信通过 `props` 进行传递
        
    *   也包含通过 `Context` 进行数据之间的共享
        
    *   `React` 次要负责帮忙咱们治理视图,`state` 如何保护最终还是咱们本人来决定
        

![](https://gitee.com/xmkm/cloudPic/raw/master/img/20201005132319.png)
  • Redux就是一个帮忙咱们治理 State 的容器:

    
    *   `Redux` 是 `JavaScript` 的状态容器, 提供了可预测的状态治理
        
  • Redux除了和 React 一起应用之外, 它也能够和其余界面库一起来应用(比方Vue), 并且它十分小 (包含依赖在内,只有 2kb)

Redux 的核心理念 -Store

  • Redux的核心理念非常简单

  • 比方咱们有一个敌人列表须要治理:

    
    *   ** 如果咱们没有定义对立的标准来操作这段数据,那么整个数据的变动就是无奈跟踪的 **
        
    *   比方页面的某处通过 `products.push` 的形式减少了一条数据
        
    *   比方另一个页面通过 `products[0].age = 25` 批改了一条数据
        
  • 整个应用程序盘根错节,当呈现 bug 时,很难跟踪到底哪里产生的变动

Redux 的核心理念 -action

  • Redux要求咱们通过 action 来更新state

    
    *   ** 所有数据的变动, 必须通过 **`dispatch` 来派发 `action` 来更新
        
    *   `action` 是一个一般的 `JavaScript` 对象,用来形容这次更新的 `type` 和 `content`
        
  • 比方上面就是几个更新 friendsaction:

    
    *   强制应用 `action` 的益处是能够清晰的晓得数据到底产生了什么样的变动,所有的数据变动都是可跟追踪、可预测的
        
    *   当然,目前咱们的 `action` 是固定的对象,实在利用中,咱们会通过函数来定义,返回一个 `action`
        

Redux 的核心理念 -reducer

  • 然而如何将 stateaction分割在一起呢? 答案就是reducer

    
    *   `reducer` 是一个纯函数
        
    *   `reducer` 做的事件就是将传入的 `state` 和 `action` 联合起来来生成一个新的 `state`
        

Redux 的三大准则

  • 繁多数据源

    
    *   整个应用程序的 `state` 被存储在一颗 `object tree` 中, 并且这个 `object tree` 只存储在一个 `store`
        
    *   `Redux` 并没有强制让咱们不能创立多个 `Store`,然而那样做并不利于数据的保护
        
    *   繁多的数据源能够让整个应用程序的 `state` 变得不便保护、追踪、批改
        
  • State 是只读的

    
    *   惟一批改 `state` 的办法肯定是触发 `action`, 不要试图在其它的中央通过任何的形式来批改 `state`
        
    *   这样就确保了 `View` 或网络申请都不能间接批改 `state`,它们只能通过 `action` 来形容本人想要如何批改 `state`
        
    *   这样能够保障所有的批改都被集中化解决,并且依照严格的程序来执行,所以不须要放心 `race condition`(竟态)的问题
        
  • 应用纯函数来执行批改

    
    *   通过 `reducer` 将旧 `state` 和 `action` 分割在一起, 并且返回一个新的 `state`
        
    *   随着应用程序的复杂度减少,咱们能够将 `reducer` 拆分成多个小的 `reducers`,别离操作不同 `state tree` 的一部分
        
    *   然而所有的 `reducer` 都应该是纯函数,不能产生任何的副作用
        

Redux 的根本应用

Redux 中外围的 API

redux的装置: yarn add redux

  1. createStore 能够用来创立 store对象

  2. store.dispatch 用来派发 action, action会传递给 store

  3. reducer接管 action,reducer 计算出新的状态并返回它 (store负责调用reducer)

  4. store.getState 这个办法能够帮忙获取 store 里边所有的数据内容

  5. store.subscribe办法能够让让咱们订阅 store 的扭转,只有 store 产生扭转,store.subscribe 这个 函数接管的这个回调函数 就会被执行

小结

  1. 创立sotore, 决定 store 要保留什么状态

  2. 创立action, 用户在程序中实现什么操作

  3. 创立reducer, reducer 接管 action 并返回更新的状态

Redux 的应用过程

  1. 创立一个对象, 作为咱们要保留的状态

  2. 创立 Store 来存储这个state

    
    *   创立 `store` 时必须创立 `reducer`
        
    *   咱们能够通过 `store.getState` 来获取以后的 `state`
        
  3. 通过 action 来批改state

    
    *   通过 `dispatch` 来派发 `action`
        
    *   通常 `action` 中都会有 `type` 属性,也能够携带其余的数据
        
  4. 批改 reducer 中的解决代码

    
    *   这里肯定要记住,`reducer` 是一个 ** 纯函数 **,不能间接批改 `state`
        
    *   前面会讲到间接批改 `state` 带来的问题
        
  5. 能够在派发 action 之前,监听 store 的变动

import {createStore} from ‘redux’

// 1. 初始化 state
const initState = {counter: 0}

// 2.reducer 纯函数 不能批改传递的 state
function reducer(state = initState, action) {
switch (action.type) {
case ‘INCREMENT’:
return {…state, counter: state.counter + 1}
case ‘ADD_COUNTER’:
return {…state, counter: state.counter + action.num}
default:
return state
}
}

// 3.store 参数放一个 reducer
const store = createStore(reducer)

// 4.action
const action1 = {type: ‘INCREMENT’}
const action2 = {type: ‘ADD_COUNTER’, num: 2}

// 5. 订阅 store 的批改
store.subscribe(() => {
console.log(‘state 产生了扭转: ‘, store.getState().counter)
})

// 6. 派发 action
store.dispatch(action1)
store.dispatch(action2)

Redux 构造划分

  • 如果咱们将所有的逻辑代码写到一起, 那么当 redux 变得复杂时代码就难以保护

  • 对代码进行拆分, 将 store、reducer、action、constants 拆分成一个个文件

拆分目录

Redux 应用流程

Redux 官网流程图

React-Redux 的应用

redux 融入 react 代码(案例)

  • redux融入 react 代码案例:

    
    *   `Home` 组件:其中会展现以后的 `counter` 值,并且有一个 + 1 和 + 5 的按钮
        
    *   `Profile` 组件:其中会展现以后的 `counter` 值,并且有一个 - 1 和 - 5 的按钮
        

![](https://gitee.com/xmkm/cloudPic/raw/master/img/20201005132516.png)
  • 外围代码次要是两个:

    
    *   在 `componentDidMount` 中订阅数据的变动,当数据发生变化时从新设置 `counter`
        
    *   在产生点击事件时,调用 `store` 的 `dispatch` 来派发对应的 `action`
        

自定义 connect 函数

当咱们多个组件应用 redux 时, 反复的代码太多了, 比方: 订阅 state 勾销订阅 state 或 派发action 获取state

将反复的代码进行封装, 将不同的 statedispatch作为参数进行传递

// connect.js
import React, {PureComponent} from ‘react’
import {StoreContext} from ‘./context’
/**

  • 1. 调用该函数: 返回一个高阶组件
  •     传递须要依赖 state 和 dispatch 来应用 state 或通过 dispatch 来扭转 state
    *
  • 2. 调用高阶组件:
  •     传递该组件须要依赖 store 的组件
    *
  • 3. 次要作用:
  •     将反复的代码抽取到高阶组件中, 并将该组件依赖的 state 和 dispatch
  •     通过调用 mapStateToProps()或 mapDispatchToProps()函数
  •     并将该组件依赖的 state 和 dispatch 供该组件应用, 其余应用 store 的组件不用依赖 store
    *
  • 4.connect.js: 优化依赖
  •     目标: 然而下面的 connect 函数有一个很大的缺点:依赖导入的 store
  •     优化: 正确的做法是咱们提供一个 Provider,Provider 来自于咱们
  • Context,让用户将 store 传入到 value 中即可;
    */

export function connect(mapStateToProps, mapDispatchToProps) {
return function enhanceComponent(WrapperComponent) {
class EnhanceComponent extends PureComponent {
constructor(props, context) {
super(props, context)

// 组件依赖的 state
this.state = {
storeState: mapStateToProps(context.getState()),
}
}

// 订阅数据发生变化, 调用 setState 从新 render
componentDidMount() {
this.unsubscribe = this.context.subscribe(() => {
this.setState({
centerStore: mapStateToProps(this.context.getState()),
})
})
}

// 组件被卸载勾销订阅
componentWillUnmount() {
this.unsubscribe()
}

render() {
// 上面的 WrapperComponent 相当于 home 组件(就是你传递的组件)
// 你须要将该组件须要依赖的 state 和 dispatch 作为 props 进行传递
return (
<WrapperComponent
{…this.props}
{…mapStateToProps(this.context.getState())}
{…mapDispatchToProps(this.context.dispatch)}
/>
)
}
}
// 取出 Provider 提供的 value
EnhanceComponent.contextType = StoreContext
return EnhanceComponent
}
}

// home.js
// 定义组件依赖的 state 和 dispatch
const mapStateToProps = state => ({
counter: state.counter,
})

const mapDispatchToProps = dispatch => ({
increment() {
dispatch(increment())
},
addNumber(num) {
dispatch(addAction(num))
},
})
export default connect(mapStateToProps,mapDispatchToProps)(依赖 redux 的组件)

react-redux 应用

  • 开始之前须要强调一下,reduxreact 没有间接的关系,你齐全能够在 React, Angular, Ember, jQuery, or vanilla JavaScript 中应用 Redux

  • 只管这样说,redux 仍然是和 React 或者 Deku 的库联合的更好,因为他们是通过 state 函数来形容界面的状态,Redux 能够发射状态的更新,让他们作出相应。

  • 尽管咱们之前曾经实现了 connectProvider 这些帮忙咱们实现连贯 redux、react 的辅助工具,然而实际上redux 官网帮忙咱们提供了react-redux 的库,能够间接在我的项目中应用,并且实现的逻辑会更加的谨严和高效

  • 装置react-redux

    
    *   `yarn add react-redux`
        

// 1.index.js
import {Provider} from ‘react-redux’
ReactDOM.render(
<Provider store={store}>
<App />
</Provider>,
document.getElementById(‘root’)
)

// 2.home.js
import {connect} from ‘react-redux’
// 定义须要依赖的 state 和 dispatch (函数须要返回一个对象)
export default connect(mapStateToProps, mapDispatchToProps)(About)

react-redux 源码导读

Redux-Middleware 中间件

组件中异步操作

  • 在之前简略的案例中,redux中保留的 counter 是一个本地定义的数据

    
    *   咱们能够间接通过同步的操作来 `dispatch action`,`state` 就会被立刻更新。*   然而实在开发中,`redux` 中保留的 ** 很多数据可能来自服务器 **,咱们须要进行 ** 异步的申请 **,再将数据保留到 `redux` 中
        
  • 网络申请能够在 class 组件的 componentDidMount 中发送,所以咱们能够有这样的构造:

redux 中异步操作

  • 下面的代码有一个缺点:

    
    *   咱们必须将 ** 网络申请 ** 的异步代码放到组件的生命周期中来实现
        
  • 为什么将网络申请的异步代码放在 redux 中进行治理?

    
    *   前期代码量的减少,如果把网络申请异步函数放在组件的生命周期里,这个生命周期函数会变得越来越简单,组件就会变得越来越大
        
    *   事实上,** 网络申请到的数据也属于状态治理的一部分 **,更好的一种形式应该是将其也交给 `redux` 来治理
        

  • 然而在 redux 中如何能够进行异步的操作呢?

    
    *   ** 应用中间件 (Middleware)**
        
    *   学习过 `Express` 或 `Koa` 框架的童鞋对中间件的概念肯定不生疏
        
    *   在这类框架中,`Middleware` 能够帮忙咱们在 ** 申请和响应之间嵌入一些操作的代码 **,比方 cookie 解析、日志记录、文件压缩等操作
        

了解中间件(重点)

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

    
    *   这个中间件的目标是在 `dispatch` 的 `action` 和最终达到的 `reducer` 之间,扩大一些本人的代码
        
    *   比方日志记录、** 调用异步接口 **、增加代码调试性能等等
        

  • redux-thunk是如何做到让咱们能够发送异步的申请呢?

    
    *   默认状况下的 `dispatch(action)`,`action` 须要是一个 `JavaScript` 的对象
        
    *   `redux-thunk` 能够让 `dispatch`(`action` 函数), `action`** 能够是一个函数 **
        
    *   该函数会被调用, 并且会传给这个函数两个参数: 一个 `dispatch` 函数和 `getState` 函数
        
        *   `dispatch` 函数用于咱们之后再次派发 `action`
            
        *   `getState` 函数思考到咱们之后的一些操作须要依赖原来的状态,用于让咱们能够获取之前的一些状态
            

redux-thunk 的应用

  1. 装置redux-thunk

    
    *   `yarn add redux-thunk`
        
  2. 在创立 store 时传入利用了 middlewareenhance函数

    
    *   通过 `applyMiddleware` 来联合多个 `Middleware`, 返回一个 `enhancer`
        
    *   将 `enhancer` 作为第二个参数传入到 `createStore` 中
        
        ![image-20200821182447344](https://gitee.com/xmkm/cloudPic/raw/master/img/20201005132723.png)
        
  3. 定义返回一个函数的action

    
    *   留神:这里不是返回一个对象了,而是一个 ** 函数 **
        
    *   该函数在 `dispatch` 之后会被执行
        

![](https://gitee.com/xmkm/cloudPic/raw/master/img/20201005132817.png)

查看代码

redux-devtools

redux-devtools 插件

  • 咱们之前讲过,redux能够不便的让咱们对状态进行跟踪和调试,那么如何做到呢?

    
    *   `redux` 官网为咱们提供了 `redux-devtools` 的工具
        
    *   利用这个工具,咱们能够晓得每次状态是如何被批改的,批改前后的状态变动等等
        
  • 应用步骤:

    
    *   第一步:在浏览器上装置 [redux-devtools](https://chrome.google.com/webstore/detail/redux-devtools/lmhkpmbekcpmknklioeibfkpmmfibljd/related?utm_source=chrome-ntp-icon) 扩大插件
        
    *   第二步:在 `redux` 中集成 `devtools` 的中间件
        

// store.js 开启 redux-devtools 扩大
import {createStore, applyMiddleware, compose} from ‘redux’

// composeEnhancers 函数
const composeEnhancers =
window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__({trace: true}) || compose

// 通过 applyMiddleware 来联合多个 Middleware, 返回一个 enhancer
const enhancer = applyMiddleware(thankMiddleware)

// 通过 enhancer 作为第二个参数传递 createStore 中
const store = createStore(reducer, composeEnhancers(enhancer))

export default store

redux-sage

generator

Generator函数是 ES6 提供的一种异步编程解决方案,语法行为与传统函数齐全不同

Generator 函数有多种了解角度。语法上,首先能够把它了解成,Generator函数是一个状态机,封装了多个外部状态。

// 生成器函数的定义
// 默认返回: Generator
function* foo() {
console.log(‘111’)
yield ‘hello’
console.log(‘222’)
yield ‘world’
console.log(‘333’)
yield ‘jane’
console.log(‘444’)
}
// iterator: 迭代器
const result = foo()
console.log(result)

// 应用迭代器
// 调用 next, 就会耗费一次迭代器
const res1 = result.next()
console.log(res1) // {value: “hello”, done: false}
const res2 = result.next()
console.log(res2) // {value: “world”, done: false}
const res3 = result.next()
console.log(res3) // {value: “jane”, done: false}
const res4 = result.next()
console.log(res4) // {value: undefined, done: true}

redux-sage 流程

redux-saga 的应用

  • redux-saga是另一个比拟罕用在 redux 发送异步申请的中间件, 它的应用更加的灵便

  • Redux-saga的应用步骤如下

    
    1.  装置 `redux-sage`: `yarn add redux-saga`
        
    2.  集成 `redux-saga` 中间件
        
        *   引入 `createSagaMiddleware` 后, 须要创立一个 `sagaMiddleware`
            
        *   而后通过 `applyMiddleware` 应用这个中间件,接着创立 `saga.js` 这个文件
            
        *   启动中间件的监听过程, 并且传入要监听的 `saga`
            
    3.  `saga.js` 文件的编写
        
        *   `takeEvery`: 能够传入多个监听的 `actionType`, 每一个都能够被执行(对应有一个 `takeLatest`, 会勾销后面的)
            
        *   `put`: 在 `saga` 中派发 `action` 不再是通过 `dispatch`, 而是通过 `put`
            
        *   `all`: 能够在 `yield` 的时候 `put` 多个 `action`
            

// store.js
import createSageMiddleware from ‘redux-saga’
import saga from ‘./saga’
// 1. 创立 sageMiddleware 中间件
const sagaMiddleware = createSageMiddleware()
// 2. 利用一些中间件
const enhancer = applyMiddleware(sagaMiddleware)
const store = createStore(reducer,composeEnhancers(enhancer))

sagaMiddleware.run(saga)
export default store

// saga.js
import {takeEvery, put, all} from ‘redux-saga/effects’
import {FETCH_HOME_DATA} from ‘./constant’

function* fetchHomeData(action) {
const res = yield axios.get(‘http://123.207.32.32:8000/hom…
const banners = res.data.data.banner.list
const recommends = res.data.data.recommend.list
// dispatch action 提交 action,redux-sage 提供了 put
yield all([
yield put(changeBannersAction(banners)),
yield put(changeRecommendAction(recommends)),
])
}

function* mySaga() {
// 参数一: 要拦挡的 actionType
// 参数二: 生成器函数
yield all([
takeEvery(FETCH_HOME_DATA, fetchHomeData),
])
}

export default mySaga

reducer 代码拆分

Reducer 代码拆分

  • 咱们来看一下目前咱们的reducer

    
    *   以后这个 `reducer` 既有解决 `counter` 的代码,又有解决 `home` 页面的数据
        
    *   后续 `counter` 相干的状态或 `home` 相干的状态会进一步变得更加简单
        
    *   咱们也会持续增加其余的相干状态,比方购物车、分类、歌单等等
        
    *   如果将所有的状态都放到一个 `reducer` 中进行治理,随着我的项目的日趋宏大,必然会造成代码臃肿、难以保护
        
  • 因而, 咱们能够对 reducer 进行拆分:

    
    *   咱们先抽取一个对 `counter` 解决的 `reducer`
        
    *   再抽取一个对 `home` 解决的 `reducer`
        
    *   将它们合并起来
        

Reducer 文件拆分

  • 目前咱们曾经将不同的状态解决拆分到不同的 reducer 中,咱们来思考:

    
    *   尽管曾经放到不同的函数了,然而这些函数的解决仍然是在同一个文件中,代码十分的凌乱
        
    *   另外对于 `reducer` 中用到的 `constant`、`action` 等咱们也仍然是在同一个文件中;

combineReducers 函数

  • 目前咱们合并的形式是通过每次调用 reducer 函数本人来返回一个新的对象

  • 事实上,redux给咱们提供了一个 combineReducers 函数能够不便的让咱们对多个 reducer 进行合并

import {combineReducers} from ‘redux’
import {reducer as counterReducer} from ‘./count’
import {reducer as homeReducer} from ‘./home’

export const reducer = combineReducers({
counterInfo: counterReducer,
homeInfo: homeReducer,
})

  • 那么 combineReducers 是如何实现的呢?

    
    *   它将咱们传递的 `reducer` 合并成一个对象, 最终返回一个 `combination` 函数
        
    *   在执行 `combination` 函数过程中, 会通过判断前后返回的数据是否雷同来决定返回之前的 `state` 还是新的 `state`
        

immutableJs

数据可变形的问题

  • React 开发中,咱们总是会强调数据的不可变性:

    
    *   无论是类组件中的 `state`,还是 `reduex` 中治理的 `state`
        
    *   事实上在整个 `JavaScript` 编码的过程中,数据的不可变性都是十分重要的
        
  • 数据的可变性引发的问题(案例):

    
    *   咱们明明没有批改 obj,只是批改了 obj2,然而最终 obj 也被咱们批改掉了
        
    *   起因非常简单,对象是援用类型,它们指向同一块内存空间,两个援用都能够任意批改
        

const obj1 = {name: ‘jane’, age: 18}
const obj2 = obj1
obj1.name = ‘kobe’
console.log(obj2.name) // kobe

  • 有没有方法解决下面的问题呢?

    
    *   进行对象的拷贝即可:`Object.assign` 或扩大运算符
        
  • 这种对象的浅拷贝有没有问题呢?

    
    *   从代码的角度来说,没有问题,也解决了咱们理论开发中一些潜在危险
        
    *   从性能的角度来说,有问题,如果对象过于宏大,这种拷贝的形式会带来性能问题以及内存节约
        
  • 有人会说,开发中不都是这样做的吗?

    
    *   从来如此,便是对的吗?

意识 ImmutableJS

  • 为了解决下面的问题,呈现了 Immutable 对象的概念:

    
    *   `Immutable` 对象的特点是只有批改了对象,就会返回一个新的对象,旧的对象不会产生扭转;
  • 然而这样的形式就不会节约内存了吗?

    
    *   为了节约内存,又呈现了一个新的算法:`Persistent Data Structure`(长久化数据结构或一致性数据结构)
  • 当然,咱们一听到长久化第一反馈应该是数据被保留到本地或者数据库,然而这里并不是这个含意:

    
    *   用一种数据结构来保留数据
        
    *   当数据被批改时,会返回一个对象,然而 ** 新的对象会尽可能的利用之前的数据结构而不会对内存造成节约 **,如何做到这一点呢?构造共享:

  • 装置Immutable: yarn add immutable

ImmutableJS 常见 API

留神:我这里只是演示了一些 API,更多的形式能够参考官网

作用:不会批改原有数据结构,返回一个批改后新的拷贝对象

  • JavaScripImutableJS 间接的转换

    
    *   对象转换成 `Immutable` 对象:`Map`
        
    *   数组转换成 `Immtable` 数组:`List`
        
    *   深层转换:`fromJS`
        

const im = Immutable
// 对象转换成 Immutable 对象
const info = {name: ‘kobe’, age: 18}
const infoIM = im.Map()

// 数组转换成 Immtable 数组
const names = [“abc”, “cba”, “nba”]
const namesIM = im.List(names)

  • ImmutableJS的基本操作:

    
    *   批改数据:`set(property, newVal)`
        
        *   返回值: 批改后新的数据结构
            
    *   获取数据:`get(property/index)`
        
    *   获取深层 `Immutable` 对象数据(子属性也是 `Immutable` 对象): `getIn(['recommend', 'topBanners'])`
        

// set 办法 不会批改 infoIM 原有数据结构,返回批改后新的数据结构
const newInfo2IM = infoIM.set(‘name’, ‘james’)
const newNamesIM = namesIM.set(0, ‘why’)

// get 办法
console.log(infoIM.get(‘name’))// -> kobe
console.log(namesIM.get(0))// -> abc

联合 Redux 治理数据

  1. ImmutableJS重构redux

    
    *   yarn add Immutable
        
    *   yarn add redux-immutable
        
  2. 应用 redux-immutable 中的 combineReducers;

  3. 所有的 reducer 中的数据都转换成 Immutable 类型的数据

FAQ

React 中的 state 如何治理

  • 目前我的项目中采纳的 state 治理计划(参考即可):

    
    *   相干的组件外部能够保护的状态, 在组件外部本人来保护
        
    *   只有是须要共享的状态, 都交给 redux 来治理和保护
        
    *   从服务器申请的数据(包含申请的操作) , 交给 redux 来保护
正文完
 0