小程序中 Redux 的使用

作者 | 张鹏

640?wx_fmt=jpeg

Android 程序员,关注大前端各种新兴技术。


在我们的一款小程序中聊天部分主要是基于 Redux 来维护数据部分的。为什么使用了 Redux ?这也是符合了使用 Redux 的一些原则的。那么哪些情况使用 Redux 比较好呢?

用户的使用方式复杂

不同身份的用户有不同的使用方式(比如普通用户和管理员)

多个用户之间可以协作

与服务器大量交互,或者使用了 WebSocket

View 要从多个来源获取数据

我们的聊天功能基于 WebSocket 交互数据,使用方式较为复杂,多个地方都会影响聊天呈现的数据内容。并且与服务器交互量比较大,UI 上呈现的内容受到多个地方的影响。如下图:

640?wx_fmt=png

图中展示了 Redux 的三大块业务实现部分与业务部分的交互逻辑,其中数据会反应在首页和聊天界面,而首页及聊天界面的一些操作又会通过 Action 反馈到 Redux 的数据对象上。另外 Websocket 和 Http 网络部分也会有很多数据反馈到 Redux 的数据对象上。

Redux 设计思想

简单总结为两句话:

(1)Web 应用是一个状态机,视图与状态是一一对应的。

(2)所有的状态,保存在一个对象里面。

Redux 的三大原则

  1. 单一数据源

  2. State 是只读的

  3. 使用纯函数来执行修改

其工作逻辑如下图所示:

640?wx_fmt=jpeg

Store

Store 就是保存数据的地方,你可以把它看成一个容器。整个应用只能有一个 Store。

import { createStore } from 'redux';
const store = createStore(fn);

通过 Store 可以获取到 State 对象,State 为时点的数据集合,即 Store 的一个快照。

import { createStore } from 'redux';
const store = createStore(fn);

const state = store.getState();

Action

State 的变化,会导致 View 的变化。但是,用户接触不到 State,只能接触到 View。所以,State 的变化必须是 View 导致的。Action 就是 View 发出的通知,表示 State 应该要发生变化了。

const action = {
   type: 'ADD_TODO',    payload: 'Learn Redux'
};

Dispatch

store.dispatch()是 View 发出 Action 的唯一方法。

import { createStore } from 'redux';


const store = createStore ( fn ); store . dispatch ({ type : 'ADD_TODO' , payload : 'Learn Redux'
});

Subscribe

Store 允许使用store.subscribe方法设置监听函数,一旦 State 发生变化,就自动执行这个函数。

import { createStore } from 'redux';
const store = createStore(reducer);

store.subscribe(listener);

小程序

在 Redux 的使用中我们主要会去实现两个部分,一是 Action 部分,去构造定义要发送的 Action 的数据格式等,另一部分是 Reducer 部分,即 Dispatch 分发的 Action 的具体相应处理部分。Reducer 即接收原 State 和 Action,根据当前 Action 重新创建一份新的 State,然后返回这个 State。

消息的处理逻辑一开始并不是很好,发送消息、接收消息、发送中、接收中等各种消息的状态,都会单独发送不同的 Action 这也导致 Reducer 的维护变得非常困难,而且导致很多不一致的地方。

640?wx_fmt=png

后来改为一个 Action 做统一处理,处理起来简单了很多,将原有的多种 Action,多种接收 Action 并处理的逻辑统一成一种,当然如果是维护的不同数据那么还是需要分开来处理的。

修改后 Action 的实现

修改后消息 Action 接口如下:

onMessage(message, doctorId)

如两处修改消息 Action 的使用:

  • 接收消息,WebSocket 接收到新的消息时,因为接收到的消息分为发送出去的,和接收到的两种:

onMessage({
   ...message, sending: { status: 0 }}, message.from === config.patientId ? message.to : message.from
);
  • 发送消息,本地发送消息时,将其更新到界面上,并调用WebSocket发送接口将其发送出去。

const sendText = async (doctorId, text) => {
  const message = {
    typ: MSG.TEXT,
    content: toRealText(text),
    to: doctorId,
    mine: true,
    sending: {
      status: 1
    },
    guid: guid(),
    from: config.patientId,
    created: Date.now()
  }
  onMessage(message, doctorId)
}
修改后 Reducer 的实现

在 Reducer 统一提供一处消息 Action 的处理方式,避免之前的多处处理导致的数据不一致的情况:

[CHAT_MESSAGE] (_state, _action) {

   // 拷贝一份 state let state = {..._state};
   // 提取消息参数 _handle(_state, _action); // 处理消息对象 // 修改 state // ... return state;
}
修改后 UI 订阅状态

最后我们需要将 State 中维护的数据对象显示到 UI 上,在 Javascript 中我们可以使用 @connect 在页面上加上修饰,通过 @connect 实现内容的 subscribe 过程,将 messages 方法注入到页面中的 data 中。

@connect({
    messages(state) {
      const chat = state.chat[this.doctorId];
      if (chat) {
        return chat.messages;
      }
      return [];
    }
})

对于首页也是同样的道理,在首页不需要消息列表,但是需要小时列表的摘要信息以显示有多少种消息列表。也即当前维护着的对话数量。

@connect({
   sessions(state) { let sessions = [] for (let id in state.chat) { let session = state.chat[id] sessions.push(session.session) } sessions.sort((a, b) => { return b.updated - a.updated }) return sessions }
});

总结

小程序里使用到的内容较为简单,Redux 原本也就是简化 Web 中状态和界面简单对应关系,使用时只需要关注其三大原则即可。并尽可能地统一相同的修改操作,保持数据的统一性。

参考

http://www.redux.org.cn/

http://www.ruanyifeng.com/blog/2016/09/redux_tutorial_part_one_basic_usages.html


全文完



以下文章您可能也会感兴趣:


我们正在招聘 Java 工程师,欢迎有兴趣的同学投递简历到 rd-hr@xingren.com 。


640?wx_fmt=png


杏仁技术站

长按左侧二维码关注我们,这里有一群热血青年期待着与您相会。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值