Coder Social home page Coder Social logo

cnyballk / wenaox Goto Github PK

View Code? Open in Web Editor NEW
35.0 2.0 4.0 1.05 MB

:dolphin: A light weight and good performance micro channel small program state management library

License: MIT License

JavaScript 98.05% Shell 1.95%
wechat wenaox immer weapp redux vuex diff setdata miniprograms miniprogram-component

wenaox's Introduction

Wenaox

NPM version

npm download

一个轻量性能好的微信小程序的状态管理库(已有多个线上项目)

该库我已不再维护,但需要的话可以提pr或者各自fork单独修改

前言

工作中在开发小程序的时候,发现组件间通讯或跨页通讯会把程序搞得混乱不堪,变得极难维护和扩展,setData 的性能不是很好,浪费很多的资源,所以封装了一个 wenaox 作为使用,后决定开源出来给大家使用 如果觉得有什么问题或者建议,欢迎提 issue 和 pr,觉得不错,可以给个 star,鼓励一下 2333

特点

  • 支持中间件
  • 中大型项目可多个 contro 区分模块
  • asyncs 自带 loading
  • 轻量、性能好

性能

  • 每次更新数据确保后台态页面停止刷新数据而在重新进入前台的时候开始
  • 采取 diff 新旧数据,保证一次只更新最少量的数据

开始

安装

虽然可以直接引入,但是建议使用 npm 安装开发,将会很方便

npm i -S wenaox
or
yarn add wenaox

关于小程序如何构建 npm

实例化 store

新建一个 store.js

import { Store } from "wenaox";
//数据
const state = {
	count: 0,
};
//方法
const methods = {
	//修改state的方法(只允许通过syncs的方法进行修改)
	syncs: {
		addCount(state, payload) {
			state.count = state.count + 1;
		},
	},
	//包含副作用的方法
	asyncs: {
		asyncAddCount(payload, rootState) {
			setTimeout(() => {
				this.addCount(c);
			});
		},
	},
};
//注册store
const store = new Store({ state, methods });

store 中的 state 和 methods 打印如下:

{
  "state": { "count": 0 },
  "methods": { "addCount": fn, "asyncAddCount": fn }
  //略
}

在中大型小程序中的实践

在中大型小程序中的实践中,共享的状态和方法将会很多,如果全部都定义在一起会很混乱,所以提供一个多 contro 的机制,可以根据页面或者功能来进行划分

// 下面是多 contro 的注册写法

 const store = new Store({ controA: { state, methods } });

将会 Store 对 store 的 state 和 methods 通过 contro 的变量名进行一个细化区分:

{
  "state": { "controA": { "count": 0 } },
  "methods": { "controA": { "addCount": fn, "asyncAddCount": fn } }
  //略
}

在 app 中初始化

//app.js
import { Provider } from "wenaox";
import store from "xxx路径/store";

const appConfig = {
	//some config
};
App(Provider(store)(appConfig));

创建页面

-在 page.js 中连接 state 和 methods

import { orm } from 'wenaox';

// 返回需要的state和methods
const mapState = state => ({
  count: state.count,
});
const mapMethods = methods => ({
  addCount: methods.addCount,
  asyncAddCount: methods.asyncAddCount,
});
const pageConfig = {
  //some config
};
// 使用orm连接
Page(orm(mapState, mapMethods)(pageConfig));
  • 在 page.wxml 中使用
<view class="count">count</view>
<button bindtap="addCount">count + 1</button>
<button bindtap="asyncAddCount">async count + 1</button>

点击按钮就会发生变化!一个简单的计数器!

在自定义组件中使用

由于小程序中的属性没有分辨组件还是 page 页面所以我另外写了一个对 自定义组件 的方法就是 ormComp

所以在自定义组件中使用的话仅仅只需要 js 中的 orm 替换成 ormComp 就可以了

Component(ormComp(mapState, mapMethods)(compConfig));

跨页面同步数据

使用 wenaox 你不用关心跨页数据同步,任何地方的修改,都会同步到使用到的地方[仅限于正在显示的页面/组建]

这是因为 wenaox 在页面栈中 hide 的页面不执行更新,而是等待 onshow 事件才重新进行更新,这是为了更好的性能

支持 async await 以及 laoding

在头部引入 regeneratorRuntime 即可使用 async/await

import { regeneratorRuntime } from  'wenaox'

const methods = {
  // ...略
  asyncs: {
    async asyncAddCount(payload, rootState) {
      await new Promise(resolve => {
        setTimeout(resolve, 2000);
      });
      this.addCount(1);
    },
  },
};

而在使用 async/await 之后自动会生成一个 loading 变量

{
  "loading": state.loading.asyncAddCount
}

可以在 mapState 中引入,再也不用手动写 loading 了!! 当然你不用的话,你不引入 对应的 loading 变量的话,wenaox 也不会再对 对应的 loading 进行更新,避免性能损失

支持中间件

wenaox 为了方便,提供了中间件的一个开发和使用,下面是一个 wenaox 的一个 log 的中间件

保证流动完所有的中间件才进行更新数据

const log = (store) => (next) => (fn, payload) => {
	console.group("改变前:", store.state);
	next(fn, payload);
	console.log("改变后:", store.state);
	console.groupEnd();
};

支持小程序自定义的 tabbar 的数据更新

小程序是可以自定义 tabbar 的,通过 wenaox 可以随时更改底部的 tab 的数量以及跳转的方法

所有的具体在下面的例子中也有展示

例子

计数器

联系我

Change Log

  • v1.3.1
    • [修复] wenaox 的多 control 的解析
  • v1.3.0
    • [修复] wenaox 的组件内部变量挂载在实例
  • v1.2.1
    • [修复] 当进入页面时不触发 mapState 判断
  • v1.2.0
    • [修复] 旧 data 不初始化
  • v1.1.1
    • [修复] 页面返回不更新数据
  • v1.1.0
    • [重构] data 直接绑定,增快速度
    • [不兼容] page 页中初始化 mapState 将不再提供 options 参数
  • v1.0.0
    • [兼容] 自定义 tabbar 的 custom-tab-bar 组件的数据绑定
    • [修复] 由于 newState 导致的生命周期的重复

开源协议

MIT

wenaox's People

Contributors

cnyballk avatar songsf520 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar

wenaox's Issues

分包后的子页面第二次无法触发onShow事件

问题描述
使用wenaox,orm连接页面后第一次进入页面正常触发onLoad,onShow事件,返回后再次进入页面后第二次只触发了onLoad事件,无触发onShow事件.
经过刚刚的测试,发现在mapState为空是就不触发onshow事件了。

const mapState = ({ user }) => ({
  // 这个不会触发onShow
});
const mapState = ({ user }) => ({
  data: user.data, // 这个正常触发onShow
});

wenaox版本: "wenaox": "^0.4.4"

page.js

import { orm } from 'wenaox';

const pageConfig = {
  data: {

  },
  onLoad() {
    console.warn('onLoad')
  },
  onShow() {
    console.warn('onShow')
  },
  onShareAppMessage() {
  },
};

Page(orm(({}) => ({}),({}) => ({}))(pageConfig));

app.json

"subpackages": [
    {
      "root": "pages/user/",
      "pages": [
        "about/index"
      ]
    }
]

当存在模块的情况,必须使用模块来取值?

版本:最新
比如这种情况
// moduleA.js
const state = { numA:1 } const methods = { syncs: { addNumA(state,payload) { state.numA += payload } }, asyncs: {} } export default {state,methods}

// store.js
`
import {Store} from 'wenaox'
import moduleA from './module-a/index'

const state = {
num:10
}
const methods = {
syncs: {
addNum(state,payload) {
state.num += payload
}
},
asyncs: {}
}

const store = new Store({state,methods, moduleA });

export default store
`

// index.js
`
import {ormComp} from 'wenaox'

const mapState = state =>({
number: state.num,
num: state.moduleA.numA
})
const mapMethods = methods => ({
addNum: methods.addNum,
addNumA: methods.moduleA.addNumA
})

Component(ormComp(mapState,mapMethods)({
data:{},
methods:{
clickBtn() {
this.addNum(12)
},
clickBtn2() {
this.addNumA(5)
}
}
}));

`
这种情况就报错,‘Cannot read property 'numA' of undefined’,如果store.js中这样导出

const store = new Store({globle:{state,methods},moduleA }); 取值都按照模块来取值则正常

Cannot read property 'syncs' of undefined

import {
  Store,
  Provider
} from 'wenaox';
const state = {
  count: 0,
};
const methods = {
  syncs: {
    addCount(state, payload) {
      state.count = state.count + 1;
    },
    subtractCount(state, payload) {
      state.count = state.count - 1;
    },
  },
  asyncs: {
    async asyncAddCount(payload, rootState) {
      const c = await new Promise(resolve => {
        setTimeout(() => {
          resolve(1);
        }, 2000);
      });
      this.addCount(c);
    },
  },
};
//一个打印state改变前后的log中间件
const log = store => fn => next => payload => {
  console.group('改变前:', store.state);
  next(fn, payload);
  console.log('改变后:', store.state);
  console.groupEnd();
};
//使用Store注册store  第一个参数为控制器对象,第二个参数为中间件数组
const store = new Store({
  state,
  methods
}, [log]);


const appConfig = ({
  onLaunch: function () {
    // 展示本地存储能力
    var logs = wx.getStorageSync('logs') || []
    logs.unshift(Date.now())
    wx.setStorageSync('logs', logs)

    // 登录
    wx.login({
      success: res => {
        console.log(res)
        // 发送 res.code 到后台换取 openId, sessionKey, unionId
      }
    })
    // 获取用户信息
    wx.getSetting({
      success: res => {
        if (res.authSetting['scope.userInfo']) {
          // 已经授权,可以直接调用 getUserInfo 获取头像昵称,不会弹框
          wx.getUserInfo({
            success: res => {
              // 可以将 res 发送给后台解码出 unionId
              this.globalData.userInfo = res.userInfo

              // 由于 getUserInfo 是网络请求,可能会在 Page.onLoad 之后才返回
              // 所以此处加入 callback 以防止这种情况
              if (this.userInfoReadyCallback) {
                this.userInfoReadyCallback(res)
              }
            }
          })
        }
      }
    })
  },
  globalData: {
    userInfo: null
  },
})

// 定义App
App(Provider(store)(appConfig));



运行后
image

bug

微信小程序的组件使用了wenaox数据缓存,缓存的数据在页面调用asyncs内的方法更新,如果在页面中使用wx:if控制组件,组件内缓存的数据没有更新(bug)。
页面代码:

未登录
点击登录

兼容性

目前发现在v6.6.7版本的微信不兼容,调试基础库2.2.0(npm从2.2.1才开始兼容),打开小程序白屏。
thirdScriptError
sdk uncaught third Error
module "models/wenaox.js" is not defined
Error: module "models/wenaox.js" is not defined

options页面url参数获取的bug

控制台输入能看上一个页面传的categoryId,但是 通过this.data.categoryId拿不到值
const mapState = ({ user }, options) => ({
//userInfo: user.userInfo
...options, // 將query混入data 先注释 BUG
});
const mapMethods = ({ user }) => ({
//getGtqUserInfo: user.getGtqUserInfo,
});

const pageConfig = {
data: {
},
onLoad(options) {
this.getListData();
},
getListData() {
//获取列表数据
let { categoryId } = this.data;
console.log(888, this.data, this.data.categoryId); // BUG
console.log(888, JSON.stringify(this.data));// BUG
//空字符串查询全部
},
};
Page(orm(mapState, mapMethods)(pageConfig));

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.