refra 是一个虚构单词, 用于指代具有可监听属性等特性, 支持响应式编程的对象模型. 本项目旨在提供一种简单的方式, 使得上层开发者可以 0 成本引入 refra 对象, 并在此之上开发应用.
npm install refra --save
以下代码依赖babel-plugin-transform-decorators-legacy插件进行转译.
import { refra, obx, action, reaction } from 'refra'
@refra
class Foobar {
@obx someProp = 0
@obx get comeComputedProp () {
return this.someProp * 2
}
@action
someAction () {
this.someProp = 1
}
@reaction('someProp')
someReaction (slice) {
console.log(slice)
}
}
类型装饰器, 用于将一个 class 转化为 refra class.
案例:
@refra
class Foobar {
// ...
}
属性装饰器, 用于将成员变量转化为可监听属性.
案例:
@refra
class Foobar {
@obx someProperty = 0
@obx get anotherProperty () {
return this.someProperty + 1
}
}
const fb = new Foobar()
console.log(fb.anotherProperty) // => 1
注意:
- 可监听属性的取值只能为 undefined, null, primitive, 以及 plain object.
- 当使用 @obx 装饰 getter 时, 将被转化为一个计算(只读)属性.
方法装饰器, 将一个成员方法转化为 action. 所谓action是指, 当一个 action 多次改变可监听属性的值时, �refra 对象只会发出一个changes
事件. action一般用来优化不必要的刷新行为.
案例:
import sleep from 'sleep-promise'
@refra
class Foobar {
@obx someProperty = 0
@obx get anotherProperty () {
return this.someProperty + 1
}
@action
async someAction () {
this.someProperty += 1
await sleep(1000)
this.someProperty += 1
await sleep(1000)
console.log(`anotherProperty = ${this.anotherProperty}.`)
}
}
const fb = new Foobar()
fb.someAction() // => anotherProperty is 3.
方法装饰器, 将一个成员方法转化为一个监听属性变化并自动运行的数据回调. 支持监听多个属性, 支持监听属性的某一字段.
注意:
- reaction 是异步执行的, 同一个事件循环内多次改变属性, reaction 只会执行一次.
案例:
import sleep from 'sleep-promise'
@refra
class Foobar {
@obx foo = { x: 0, y: 0 }
@obx bar = { x: 0, y: 0 }
@action
changeFoo () {
this.foo = { x: 0, y: 1 }
}
@action
changeBar () {
this.bar = { x: 1, y: 0 }
}
@reaction('foo')
handleFooChange ({ foo }) {
const { former, value } = foo
console.log(`foo changed, former value is ${former}, current value is ${value}.`)
}
@reaction('foo.y')
handleFooYChange ({ foo }) {
const { former, value } = foo
console.log(`foo.y changed, former value is ${former.y}, current value is ${value.y}.`)
}
@reaction ('foo', 'bar')
handleFooBarChange ({ foo, bar }) {
const { formerFoo, valueFoo } = foo
const { formerBar, valueBar } = bar
console.log(`foo changed, former value is ${formerFoo}, current value is ${valueFoo}.`)
console.log(`bar changed too, former value is ${formerBar}, current value is ${valueBar}.`)
}
}
const fb = new Foobar()
fb.changeFoo()
fb.changeBar()
refra 底层有一套用来支撑响应式特性的事件机制. 如果需要在应用层使用事件驱动机制, 可以使用 @on() 装饰器来将一个成员方法转化成一个监听事件自动运行的事件回调. 运行时使用 trigger 方法发出事件.
案例:
@refra
class Foobar {
@on('some-event-type')
handleSomeEvent (evt) {
console.log(`event callback invoked: ${evt.type}.`)
}
}
const fb = new Foobar()
fb.trigger('some-event-type') // 无参数事件
fb.trigger({ type: 'some-event-type', data: {} }) // 有参数事件
如果只需要使用事件机制不需要使用响应式特性, 可以不使用 @refra, 而是使用 @eventable 来装饰 class. 此时只能使用 @on() 装饰器.
案例:
@eventable
class Foobar {
@on('some-event-type')
handleSomeEvent (evt) {
console.log(`event callback invoked: ${evt.type}.`)
}
}
const fb = new Foobar()
fb.trigger('some-event-type')
销毁 refra 或 eventable 对象. 销毁后各种联动关系都将失效.
案例:
const fb = new Foobar()
// ...
fb.dispose()
获取可监听属性(包括计算属性)的快照.
参数:
- freezed: 为 true 时返回一个被冻结的对象.
发出事件.
参数:
- evt: 事件对象或事件类型字符串.
- sync: 是否同步发送, 默认情况下事件发送是异步的, 即发出事件后系统会启动一个 microtask 去调用事件回调, 如果设置为异步发送, 则会立即调用事件回调.
案例:
const fb = new Foobar()
fb.trigger('some-event-type') // 无参数事件
fb.trigger({ type: 'some-event-type', data: {} }) // 有参数事件
fb.trigger('some-event-type', true) // 同步发送
将 refra 对象与 react 组件连接, 当 refra对象发生变化时, 重新渲染 react 组件.
注意, 此API为兼容老项目用, 新项目不要使用此API.
参数:
- component: 组件实例.
- 监听的事件, 默认为 update.
- 监听的属性, null 或属性名数组. 如果为 null 则监听所有属性.
案例
import appStore from '../app/appStore'
import FoobarStore from './FoobarStore'
class Foobar extends React.Component {
constructor (props) {
// 简单监听
this.store = new FoobarStore()
this.store.connectReactComponent(this)
// 自定义监听
appStore.connectReactComponent(this, 'update', [ 'foo', 'bar' ])
}
render () {
return <div>
<div>{this.store.title}</div>
<div>{appStore.foo + appStore.bar}</div>
</div>
}
}
由于 refra 底层使用事件机制实现响应式特性, 所以我们可以监听到一些系统内部事件帮助应用开发.
可监听属性(包括计算属性)改变时发出的事件.
可监听属性(包括计算属性)改变时发出的事件. 用来监听某个特定的属性改变, 其中 propname 为属性名.
案例:
const fb = new Foobar()
fb.on('change:someProperty', evt => {
console.log(evt)
})
批量改变事件, 一个 action 中所有属性的改变会被合并到同一个 changes 事件中.
批量改变事件, 当一个属性改变的时候, 系统会开启一个 microtask 用来合并 change 事件, 在此 microtask 之前的 change 事件会被合并为同一个 update 事件. update 事件一般用来避免不必要的刷新.
除了装饰器, refra也支持使用 createRefraClass 函数更灵活的地定义 refra 类.
createRefraClass({ obx, action, reation, init, dispose })
参数:
- obx: 可监听属性表.
- action: action表.
- reation: reaction列表.
- init: 初始化函数.
- dispose: 清理函数.
案例
const Clazz = createRefraClass({
obx: {
foo: 42,
bar () {
return this.foo + 1
}
},
action: {
plus1 () {
this.foo += 1
}
}
reaction: [
{obx: ['foo'], onFooChange () {
console.log(`foo changed, bar = ${this.bar}.`)
}}
]
})
const obj = new Clazz()
obj.plus1()