https://github.com/tunkjs/tunk
tunkjs是一个具有状态管理功能的前端架构优化框架,提供了一个让数据处理逻辑与交互逻辑完美解耦与灵活通信的模式。
https://github.com/tunkjs/tunk
dispatch mixins oop react state-management store-tunk tunk tunk-action tunk-loader tunk-vue vue
Last synced: about 2 months ago
JSON representation
tunkjs是一个具有状态管理功能的前端架构优化框架,提供了一个让数据处理逻辑与交互逻辑完美解耦与灵活通信的模式。
- Host: GitHub
- URL: https://github.com/tunkjs/tunk
- Owner: tunkjs
- Created: 2016-09-29T01:51:16.000Z (about 9 years ago)
- Default Branch: master
- Last Pushed: 2018-11-05T06:49:07.000Z (almost 7 years ago)
- Last Synced: 2025-08-20T06:48:46.615Z (2 months ago)
- Topics: dispatch, mixins, oop, react, state-management, store-tunk, tunk, tunk-action, tunk-loader, tunk-vue, vue
- Language: JavaScript
- Homepage:
- Size: 1.15 MB
- Stars: 7
- Watchers: 1
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
Awesome Lists containing this project
README
![]()
#### tunkjs是一个具有状态管理功能的前端架构优化框架,提供了一个让数据处理逻辑与交互逻辑完美解耦与灵活通信的模式。
### 开发初衷
tunk旨在优化前端架构、提高开发体验、掰直学习曲线、降低web前端项目开发维护成本,为此做了一定的封装让其拥有必要的特性、减少特有的规则及编码细节、精简接口,入门只需要掌握几个方法的使用便可接手tunk架构项目的业务开发。
tunk架构下,你的**前端代码一般会被分为两层:数据服务层与视图表现层**,数据服务层由N个**数据服务模块**组成,视图层由仅仅负责数据展现与交互处理。视图组件面向数据服务层进行通信,包括发起服务模块的action执行,以及订阅状态更新。
接到一个业务需求你通常要做两件事,一个是根据业务需求和接口的数据逻辑**设计模块类**,另一件事是**写视图组件**。
tunk尽可能精简要暴露的API及处理的细节,让框架自身存在感更低,让你轻松上手,专注于业务的实现。
通过限制模块更新状态树的范围,无需向store描述变更,状态变更也完全可预测。
### 安装
````javascript
npm install tunk -S
````
除了tunk你还需要安装**视图框架绑定组件**跟vue绑定
````javascript
npm install tunk-vue -S
````
跟react或react native绑定````javascript
npm install tunk-react -S
````
跟微信小程序绑定````javascript
npm install tunk-wechat -S
````### 实例
----
> 场景:开发一个用户管理列表,列表中弹框查看用户详细信息
### 写个数据服务模块
````javascript
import {create, action} from 'tunk'
// 创建userAdmin服务模块
@create
class userAdmin {
constructor(){
// state属性仅用于在构造器中定义当前模块负责维护的状态字段
// 服务模块被创建后,Store状态树创建'userAdmin'节点,节点初始内容来自state
// 下面仅定义list为【状态字段】
this.state = {
list:[]
}
}
// @action 定义一个请求用户列表数据的Action
// 只有userAdmin模块的action可以更新'userAdmin'节点的状态
// 并且只能更新已存在的状态字段,即 list 字段
@action
fetchList(param){
// request 是tunk-request组件提供的模块内置方法
const res = this.request(...);
// 返回的结果可更新Store状态树 userAdmin 节点下的list字段,触发状态变更钩子
return {list: res.list};
}
@action
async getUserDetails(id){
const res = await this.request(...);
// details没有定义为状态字段,action处理结果的details字段不会更新到Store中
// 发起的action执行可获得返回结果,如:
// const details = await this.getUserDetails(id).details;
return {details: res.data};
}someFunc(){
// 获取当前模块的状态
const state = this.getState();
}
...
}
````如果你的构建环境不支持修饰器和async/await,譬如微信小程序,你可以这样写一个模块
````javascript
// 注意:这里首字母大写
import {Create, Action} from 'tunk'Create('userAdmin', {
// 注意:构造器 采用constructor(){}的写法会导致意外出错
constructor: function(){
this.state = {
list:[]
};
},
fetchList: Action(function(param) {
return this.request(...).then((res)=>{
return {list: res.list};
});
});
},
getUserDetails: Action(function(id){
return this.request(...).then((res)=>{
return {details: res.data};
});
}),
someFunc(){
const state = this.getState();
}
...
});
````----
### 下面开发个视图组件
**tunk与视图框架配合工作,需要跟视图框架绑定的组件,如tunk-vue、tunk-react、tunk-wechat**
这些绑定组件负责定义视图组件如何 **触发Action** 及如何 **将新状态注入到视图组件**。
下面你可以挑你要用到的视图框架的实例来阅读
#### Vue
````html
-
...
查看用户信息
...
export default {
// 状态订阅配置
state: {
// list 是模块userAdmin定义的状态字段,可以被视图组件订阅
// 组件被初始化后this.list将被注入当前 userAdmin.list 的状态
list: 'userAdmin.list'
},
// 代理action设置
actions:{
// 创建getDetails方法可调起模块的getUserDetails
getDetails: 'userAdmin.getUserDetails',
},
created(){
// 通过dispatch方式调起action
this.dispatch('userAdmin.fetchList');
},
methods:{
async showUserDetails(id){
// 调用action代理方法,并获得action执行结果
const details = await this.getDetails(id).details;
// 也可以通过dispatch调起action
// const details = await this.dispatch('userAdmin.getUserDetails', id).details;
}
}
}
````
>
#### React
````javascript
import { connect } from 'tunk-react'
@connect({ // 状态订阅配置
// list 是模块userAdmin定义的状态字段,可以被视图组件订阅
// 组件被初始化后this.list将被注入当前 userAdmin.list 的状态
list: 'userAdmin.list'
}, {// 代理action设置
// 创建getDetails方法可调起模块的getUserDetails
getDetails: 'userAdmin.getUserDetails'
})
export default class UserAdmin extends Component {
constructor() {
// 通过dispatch方式调起action
this.dispatch('userAdmin.fetchList');
}
async showUserDetails(id) {
// 调用action代理方法,并获得action执行结果
const details = await this.getDetails(id).details;
// 也可以通过dispatch调起action
// const details = await this.dispatch('userAdmin.getUserDetails', id).details;
}
render() {
// 以prop的方式注入到当前组件
const { list } = this.props;
return (
-
...
查看用户信息
))}
{list.map(item => (
...
)
}
}
````
#### 微信小程序
````javascript
import {Page} from 'tunk-wechat'
Page({
// 状态订阅配置,Page隐藏状态下不会被注入状态
// onShow时会重新注入已订阅的且已变更的状态
state: {
// list 是模块userAdmin定义的状态字段,可以被视图组件订阅
// 组件被初始化后this.list将被注入当前 userAdmin.list 的状态
list: 'userAdmin.list'
},
// 代理action设置
actions:{
// 创建getDetails方法可调起模块的getUserDetails
getDetails: 'userAdmin.getUserDetails'
},
// list有新状态准备注入前调用
onBeforeStateChange(newState){
// state订阅的状态数据,会被注入到this.data中
const oldListState = this.data.list;
// 返回结果可控制setData的内容
// 若没有定义onBeforeStateChange或没有返回Object内容,则默认注入newState
return {list: newState.list.concat(oldListState)}
},
onLoad(){
// 通过dispatch方式调起action
this.dispatch('userAdmin.fetchList');
},
showUserDetails(id){
// 若action为同步函数,可直接获得结果,若为异步需在then方法中获得
// 调用action代理方法,并获得action执行结果
this.getDetails(id).then(data => {
const details = data.details;
...
});
// 也可以通过dispatch调起action
// this.dispatch('userAdmin.getUserDetails', id).then(...);
}
}
````
#### 视图组件与tunk数据服务层通信
##### A. 两种方式触发模块的Action
1. 通过在设置action属性(vue/微信小程序)或connect(react)设置action注入配置,向视图组件注入Action代理方法,向视图组件注入Action代理方法
2. 使用 `this.dispatch('moduleName.actionName', [arg1, arg2, ...])`,支持异步
##### B. 两种方式获得Action处理结果
1. **被动注入**:通过设置属性`state`,可订阅不同模块的状态
2. **主动获取**:`dispatch`方法调起action,支持返回action执行结果,支持异步
### tunk状态流

### 通信
#### 视图组件与模块间通信
模块间通信和模块与组件间通信是完全解耦的,所有模块共同构成一个数据服务层,视图组件面向这个数据服务层进行通信。
**视图组件调起action的两种方式:**
1. 视图组件通常会被提供一个类似dispatch方法,这个方法仅支持调起action,如:`this.dispatch('moduleName.actionName', arg1, arg2, ...);`
2. 跟视图框架绑定的组件通常会支持`actons`组件属性,用来自动生成该组件可直接调用的action代理方法
**视图组件获得数据的两个途径:**
1. **被动注入** :订阅不同模块的状态字段,当action引起了状态变更,订阅的组件会被注入新状态
2. **主动获取** :视图组件通常会被提供一个类似dispatch方法,这个方法仅支持调返回action返回的结果
不同视图框架绑定组件的实现大同小异,具体可查看相关实例
* [tunk-react](https://github.com/tunkjs/gitbook-tunkjs/blob/master/doc/plugins/tunk-react.md)
* [tunk-vue](https://github.com/tunkjs/gitbook-tunkjs/blob/master/doc/plugins/tunk-vue.md)
* [tunk-wechat](https://github.com/tunkjs/gitbook-tunkjs/blob/master/doc/plugins/tunk-wechat.md)
### 要点
1. 对任何状态管理器来说,如果数据不会被复用或者数据量过大,不推荐你将这部分数据定义为状态来维护,状态快照的生成需要做到引用隔离,而引用隔离摆脱不了深克隆的性能损耗。
2. “主动获取”的方式不会生成状态快照,因此效率较高,可以理解这部分数据为“临时状态”,一般用完即焚,可视为传统状态流的补充。
3. 我们推荐你尽可能的把数据处理逻辑从视图层剥离开来,除了分离关注带来的好处外,假设你开发完wap版本的应用,又准备开发嵌入到原生app的RN版本或者微信小程序版本,只要包装好数据源,数据服务层是可以直接复用的。
----
[tunk](https://github.com/tunkjs/gitbook-tunkjs)