什么是 redux? 三大原则?
什么是redux
Redux 是一个基于 js 的全局可预测状态容器,主要用于现代前端框架中进行全局状态管理,能够在不同组件之间进行状态共享
Redux 常与 React 配合使用,但它并非只能用于 React,由于 Vue 官方推出了自己的状态管理库 Vuex,因此 Redux 很少在 Vue 中使用
Redux 的实现借鉴了 Flux, 如单项数据流。但又有别于 Flux,如全局单例 store
redux三大原则
-
单一数据源
store必须是唯一的,全局的state存储在单一store中 -
state是只读的
state只能通过派发action来改变 -
reducer必须是纯函数
reducer只做一件事情,通过累积的preState和当前的action计算得出新的state
相同的输入必须得到相同的结果,因此reducer必须是一个纯函数
reducer中不应该出现副作用,比如发请求
为什么要用 redux
React 的定义是"一个用于构建 UI 界面的 javascript 库",React 关注的点在于如何将状态转换为 UI(UI = fn(state)),在自带的状态管理方案中:
- state: 适用于管理自身状态,也可联合 this.props.chidren 实现 callback render
- props: 适用于父子组件传值,但父子组件嵌套过深时这种方式过于繁琐
- context: 适用于父子组件嵌套过深和兄弟组件共享状态的场景。context一般是作为局部的状态管理方案而不是全局的,因为context一旦更新,Provider下包裹的所有子组件都会重新渲染,造成性能问题
在一个复杂的应用中,数据的流向存在跨层、反向的数据流, 在交互上也存在父子、兄弟、跨组件通信, 不利于维护
而Redux只需要在最外层传入store, 内层组件即可通过props与store中的状态交互
在Redux中,数据的流动是单向的,store是全局单一的,reducer是纯函数,同样的输入得到的输出一定相同,因此状态是可预测的
什么时候用 redux
- 某个组件的状态,需要让其他组件可以随时拿到
- 一个组件需要改变另外一个组件的状态
- 如果你不确定要不要用 redux,那就一定不需要用 redux
redux基本api介绍
createStore
createStore是redux的重要组成部分, 大部分api都基于它生成
以下是createStore的形参列表
- reducer: 初始化、更新state
- preloadedState: 默认初始化state,但一般不用它而是reducer处理init action来初始化一个state
- enhancer: 一般用于applyMiddleWare增加中间件,作用是对createStore进行增强,覆盖原来的dispatch来实现一些功能上的拓展,如异步action、日志打印、异常监听
getState
获取state的唯一方式,用于返回当前最新的state
createStore内部维持了一个变量currentState,这个变量是私有的,对外部隐藏,只通过唯一接口getState对外暴露
react-redux connect方法底层也是通过这个api拿到state
dispatch
改变state的唯一方式,通过dispatch将用户的行为以action的形式通知给redux,通知redux把计算最新的状态并反馈给用户
如果你想在dispatch的前后做一些拓展功能,比如异步action,异常收集,日志打印,建议使用中间件来做一些增强
subscribe
订阅store的状态变化,当且仅当dispatch触发状态更新之后执行入参callback回调函数,通常我们使用这个api来实现redux和其他js库通信
react-redux底层在Provider中通过store.subscribe发起订阅,在state改变时,会检查子组件是否通过connect消费了store以及子组件的props有变化,如果这两个条件都满足,就使用最新的状态更新子组件,从而达到精确的最小粒度的render,相对于context一旦数据更新就渲染所有Provider包裹的子组件而言,这种处理方式在性能上显然是更优的
redux数据流向
- 初始化store,此时redux会dispatch一个type为init,payload为undefined的action并从reducer拿到最初的state
- Provider将store注入给组件,组件subscribe订阅store状态变化
- 用户dispatch动作产生, 使用dispatch派发action给store,store将action传给reducer更新状态。dispatch的前后如果有中间件会执行中间件相关的逻辑
- 状态更新发布之后通知订阅者,订阅者执行注册订阅的回调函数,在回调函数中可以通过getState拿到最新的状态render之后展现给用户,并且等待用户下一次动作