Skip to content

zoenleo/minapp-redux

Repository files navigation

minapp-redux - 微信小程序 redux 支持库

使用 100 行代码,你就可以拥有:

  • 完整 redux 支持(模块化、异步数据流流、强大的生态)🔥🔥

  • 原生 page 对象结构的 connect,类似 react-redux(较低的学习成本、便捷的移植方案)🔥🔥

  • 最小的 diff 更新 🔥🔥

实现理念

  • 为什么是 redux

redux 作为一个最好的 flux 最好的实现之一,他拥有庞大的社区支持与完善的插件支持。并且相对于 vuex 的定制化,redux 作为一个极简的状态管理系统(通过插件实现定制化),天生有易于移植、适用于任何框架的基因。事实上,本文介绍的minapp-redux也可以归属于 redux 的定制化插件之一。

  • 状态如何映射到视图

小程序框架没有类似 react 的 props 语法,并且由于桥接语法的存在,使得 JS 层只有 data 数据才能 map 到 wxml。所以minapp-redux的 connect 语法会将第一参数(stateMapFunction)返回的对象并入 page 对象定义的 data 中,使用是需要注意不能有属性重名,否则会有告警:stateMap 数据会覆盖 page 对象中定义的重名 data 属性。

  • 运行时

由于小程序规范,data 中的数据必须在初始化 page 对象时存在,minapp-redux提供的 connect 语法会在小程序初始化时调用,使用Page(connect(stateMapFun, methodMapFun)(pageObject))语法,pageObject 保持了你原本 page 对象的完整性,便于项目移植或移除minapp-redux。在后续 redux 状态改变的时候,redux api subscribe监听状态变化,并通过保存 store 实例使用 setData 更新到视图。

  • 最小的 diff 更新

minapp-redux使用了专属于小程序的 diff 更新机制,在有属性变化的时候会比较新 store 返回的 stateMap 与 page 对象中当前 data 的属性,并且抽取出变化属性的集合(丢弃相同值的属性),保证最小粒度的更新。值得注意的一点是,有时候我们会使用特别复杂的 store 对象作为 map 属性,而对这些复杂对象的 diff 对比会带来比较大的开销,所以minapp-redux使用浅比较,当遇到 map 数据类型为 Object 时,会将整个对象直接赋值更新。

  • 完整的 Redux 支持

前面说过minapp-redux只是作为一个 redux 的定制化插件存在,它没有改变任何的 redux 原有功能,任何你需要用到的无浏览器支持的 redux 插件你都可以无缝使用到你的minapp-redux项目中,例如:redux-logger、redux-thunk 等等。

  • 模块化支持

redux 本身没有提供模块化方法,minapp-redux 为了带来更好的使用体验,内置了 redux 的模块化封装,提供类似 vuex 开箱即用的模块化能力。

使用

引入

  • npm 构建

npm install minapp-redux --save

  • 直接引入

复制项目 src 文件夹下 index.js 到项目中

API

const { use, connect, connectComponent, createModule, combineModules } = require(' minapp-redux')

 /**
 * use
 * @param {Object} Store
 */

/**
* connect
* @param {Function} mapStateToData
* @param {Function} mapMethodToPage
* @return {Function}
*/

/**
 * connectComponent
 * @param {Function} mapStateToData
 * @param {Function} mapMethodToPage
 * @return {Function}
 */

/**
 * createModule
 * 创建模块 模块对象必须为一个标准对象
 * {
    name: 'xxx',
    initialState: {
    },
    asyncActions: actions => ({
      xxx: (payload: any) {
        return (dispatch, getState) => any
      }
    }),
    reducers: {
      xxx: (state, action) {
        return { ...state, ...any}
      }
    }
  }
 * 返回一个redux模块
 * @param {Object} module
 * @returns {Object}
 */

/**
 * combineModules
 * 合并 modules,module 为使用 createModule 创建
 * 合并后的 modules
 * @param {Object} modules
 * @returns {Object}
 */

如何使用?

注入 redux
// app.js
import { use } from 'minapp-redux'

// redux Store
import Store from '../../store/index'

//inject Store
use(Store)

App({
    onLaunch() {},
})
page 连接
// pages/login/index.js
import { connect } from '../../libs/minapp-redux'
import * as Actions from '../../store/userInfo/actions.js'

const stateMap = (state) => {
    const { userInfo } = state
    return {
        hasLogin: userInfo.hasLogin,
        userName: userInfo.userName,
    }
}

const methodMap = (dispatch, state) => ({
    login(userName) {
        dispatch(
            Actions.login({
                hasLogin: true,
                userName,
            })
        )
    },
})

const page = {
    data: {
        username: '',
    },
    bindUserNameChange(e) {
        this.setData({
            username: e.detail.value,
        })
    },
    bindLogin() {
        if (!this.data.username) return
        this.login(this.data.username)
        wx.navigateBack({
            delta: 1,
        })
    },
}

Page(connect(stateMap, methodMap)(page))
模块化方法
// store/modules/user.js
import { createModule } from '../../libs/minapp-redux'

export default createModule({
    name: 'user',
    initialState: {
        userInfo: {}
    },
    actions: {
        setUserInfo: v => v
    },
    asyncActions: actions => ({
        getUserInfo(userName) {
            return function(dispatch, getState) {
                return Promise.resolve({ userName, id: 1 }).then(
                    res => {
                        dispatch(actions.setUserInfo(res))
                        return res
                    },
                    err => Promise.reject(err)
                )
            }
        }
    }),
    reducers: {
        setUserInfo(state, action) {
            return { ...state, userInfo: action.payload }
        }
    }
})

// store/index.js
import { createStore, combineReducers, applyMiddleware } from '../libs/redux'
import thunk from '../libs/redux-thunk.js'
import logger from '../libs/redux-logger'
import { combineModules } from '../libs/minapp-redux'

import user from './user'

let modules = combineModules({
    user
})

let middleware = [thunk, logger]

const Store = createStore(
    combineReducers(modules.reducers),
    applyMiddleware(...middleware)
)

export const actions = modules.actions

export default Store

更具体使用可查看demo


About

No description, website, or topics provided.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Contributors 3

  •  
  •  
  •