redux入门

需要redux的原因

  • 在没有使用redux时,父子之间可通过props通信,相邻组件之间可以通过共同的父组件通信,但是相隔太远的组件需要层层相递直到找到共同的父组件才可以通信,这样的通信方式很麻烦。

  • 在存在相邻组件联动状态下,很难去同时获取各组件的数据,并且很难确保获取完各部分的数据之后再去执行下一步的时机。

  • 上货部分存在不同信息的配置组件(input,keyInfo,detailInfo,skuInfo)和最外层的控制上传button。要求点击button时获取完四个组件里的数据,然后处理下一步。没有redux的处理方案是:点击button触发getUpload,该函数里会setState saveOption的值,其他四个组件通过componentWillReceiveProps周期检测saveOption变化,从而确定button是否触发,如果触发,调用props里的getKeyInfo方法,把自己组件的数据传给父组件的getKeyInfo,而getKeyInfo里要把得到的数据放在一个公共变量config里,由于不确定组件返回数据的顺序和结束的时刻,需要每个组件传一个自己的标志,每次有一个数组返回数据时都检测公共变量里所有组件的标志,最后一个组件返回时四个标志应该都存在,此时触发之后的事件。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
<InputContainer
ifSave={this.state.saveOption}
getUpload={(ifNeedSubmit) => {
this.getUpload(ifNeedSubmit)
}}
getKeyInfo={(info) => {
this.getKeyInfo(info)
}}
/>
<KeyInfoConfig
ifSave={this.state.saveOption}
getKeyInfo={(info) => {
this.getKeyInfo(info)
}}
/>
<DetailInfoConfig
ifSave={this.state.saveOption}
getKeyInfo={(info) => {
this.getKeyInfo(info)
}}
/>
<SkuInfoConfig
ifSave={this.state.saveOption}
getKeyInfo={(info) => {
this.getKeyInfo(info)
}}
/>
<Button
className="mt10"
type="primary"
loading={this.state.loading}
onClick={() => {
this.getUpload(false);
}}
> {this.state.toPreCommitText}
</Button>
  • 当用户的信息栏也通过react实现时,这部分的组件肯定先于数据渲染出来,渲染出来之后再去改变用户的版本,剩余天数等信息。/用户通过订购弹窗购买之后,与之前直接reload不同,期望能够通过直接数据流更改信息。/开团监控轮训请求开团数据,不断修改左侧导航里开团监控后面的数字,这种场景下共享状态的数据流处理。

通过分析以上场景,我们需要redux更好的管理数据流。

基本概念介绍

react与传统组件MVC思路不同,react更强调组件化封装,不需要区分mvc,而是把他们以最小组件为单位集中在一起处理。这也是facebook认为react写起来更有优势的一个特点。
而redux+react做了数据流处理的不足之处,在一些很难处理的数据上(以上场景中各组件间很多的联系),redux相当于是做了C这一层的工作。

如果业务逻辑要求操作View的DOM,其实就是对DOM包裹的Model进行操作,例如添加或修改某个li,其本质是要添加或修改li元素中的值,这个值来自于Model。在Redux中,其实就是发起一个action。

执行action的目的虽然是修改Model,不过在Redux中,我们尽量希望遵循FP的思想设计出所谓的“纯函数”,于是Redux就引入了reducer函数,这个函数要做的事情其实就是对Model进行transform(可以考虑引入immutable.js来存储和操作Modle)。一旦Model对象发生了变化(并不是真正发生了变化,而是产生了一个新的Model),Redux就会通知React Component根据新获得的Model去重新Render。

显然,React扮演的是View的角色,Redux则是Controller,至于Model就是Redux Store中存储的State。我们要从MVC模式的角度去思考React+Redux开发,把代码需要做的每件事情想清楚,明确是谁的职责,如此才不至于在实现时走歪路,不讨好地去编写大量View的控制逻辑,尤其是那些牵涉到parent-child组件的递归关系时,可能会让前端代码炖成一锅粥。

Action

本质: 自定义的一个object tree

作用: Action 是把数据从应用传到 store 的有效载荷。它是 store 数据的唯一来源。一般来说你会通过 store.dispatch() 将 action 传到 store。

结构:type: 行为,以及另一个自定的值。

为了尽量减少在 action 中传递的数据,我们可以创建Action函数来调用,dispatch时只需要调用对应的action函数,和需要传的自定义的值。

Store

全局state的统一存储空间。

基本API介绍

Store.getState => 相当于组建内部的this.getState
Store.dispatch(action) => 相当于setState
Store.subscribe(listener) 监听 注销

Reducer

Reducers 指定了应用状态的变化如何响应 actions 并发送到 store 的,记住 actions 只是描述了有事情发生了这一事实,并没有描述应用如何更新 state。

纯函数,保持 reducer 纯净非常重要。永远不要在 reducer 里做这些操作:

  • 修改传入参数;
  • 执行有副作用的操作,如 API 请求和路由跳转;
  • 调用非纯函数,如 Date.now() 或 Math.random()。

Redux 首次执行时,state 为 undefined,此时我们可借机设置并返回应用的初始 state。

redux生命周期

  1. 调用 store.dispatch(action)。
  2. Redux store 调用传入的 reducer 函数。
  3. 根 reducer 应该把多个子 reducer 输出合并成一个单一的 state 树。
  4. Redux store 保存了根 reducer 返回的完整 state 树。

其他

  1. connect代替subscribe - subscribe的缺点是任意一次dispatch都会触发所有的subscribe 可以用connect代替掉 Provider
  2. redux-thunk 结合 applyMiddleware 实现异步Action,不过项目不是刚需,因为目前已经使用async await,所以数据放在action处理不是特别刚需
  3. redux可不搭配react 在各框架中使用

项目面前的使用

  1. 订购弹窗的显示
  2. 导航栏鼠标移动显示的菜单栏 (店铺管理,切换店铺,二维码)

    1
    2
    3
    4
    5
    6
    7
    {
    ifShow: true, //控制是否显示
    style: {
    right: '200px' //控制显示的位置
    },
    type: 'shopControl' //控制子元素,菜单内容
    }
  3. 开团监控数字的显示

  4. 店铺列表数据获取
  5. 用户信息(信息栏版本/登录栏显示)