乐趣区

关于react.js:React的plume2使用

Hello, plume2.

import React, {Component} from 'react'

import {Actor,Store,StoreProvider,Relax,ViewAction} from 'plume2'


//MapReduce  
class HelloActor extends Actor{defaultState(){return {text:"Hello,plume2"}
    }
}

//reactive ui event 反应式 ui 事件
class AppViewAction extends ViewAction{sayHello = (text:any) =>{this.store.dispatch('say:hello',text)
    }
}


// Single Data Source 繁多数据源
class AppStore extends Store{
    //bind data transform 绑定数据转换
    bindActor(){
        //after plume2   directly pass Actor class 间接通过 Actor 类
        return [HelloActor]
    }

    //bind ui event 绑定 ui 事件
    bindViewAction(){
        return {AppViewAction}
    }
}

//Auto compute relaxProps 主动计算关上 Props
@Relax 
 class Text extends React.Component{
    static relaxProps = {//auto injected by store.state().get('text')  由 store.state().get('text')主动注入
        text:"text",
        //auto injected by store's bindViewAction 由 store 的 bindViewAction 主动注入
        ViewAction:'viewAction'
    }
    _handleClick = () =>{const {text,viewAction} = this.props.relaxProps
        viewAction.AppViewAction.sayHello(text)
    }
    render(){const {text,viewAction} = this.props.relaxProps;
        return (<div onClick={this._handleClick}>{text}</div>
        )
    }
}

@StoreProvider(AppStore) // 应用程序入口
export default class Index extends Component {render() {
        return (
            <div>
                <Text/>
            </div>
        )
    }
}

API Actor

Actor 计算模型,一个独立的计算单元,次要作用就是转换咱们的状态数据

import {Actor,Action} from 'plume2'

// 是的  这就是一个 Actor 简略世界
class HelloActor extends Actor{
    // 畛域的初始数据  该数据会被主动的转换为 immutable
    defaultState(){
        // 返回的对象会被主动的转化为 immutable
        // 除非有非凡数据结构如(set OrderedMap 之类)
        // 不须要非凡指定 immutable 数据结构
        return {text:'hello plume2'}
    }
    //**  通过 @Action 来建设 store 的 dispatch 和 actor 的 handler(处理程序)之间的关联
    // API 标准
    // @param state actor 上一次的 immutable 状态
    // @param text  store dispatch 的参数值  尽量放弃单值设计
    @Action('change:text')
    change(state,text){
        // immutable api
        return state.set('text',text)
    }

}

Store

什么是 Store?
Store 咱们的数据状态容器核心 治理着整个 app 的数据的生命周期
咱们坚守单根数据源的思维(single data source),store 中放弃着残缺的业务与 UI 状态
Stor 的主要职责:
1 聚合 actor
2 分派 actor(单分派 事务分派)
3 通过 bigQuery 计算咱们的查询语言(QL/PQL)
4 响应页面的事件(ViewAction)
5 注册响应 RL

import {Store,ViewAction} from 'plume2'
import LoadingActor from 'loading-actor'
import UserActor from 'user-actor'
import TodoActor from 'todo-actor'


// 响应页面事件的逻辑解决
class AppViewAction extends ViewAction {
    //show simple dispatch 显示简略分派
    // when dispatch finished if status had changed,  如果状态已更改,则在调度实现时,//each Relax component received message 每个组件都接管到音讯
    update = () => {
        // 将计算的工作分派的到 actor
        // 而后依据 actor 的返回值 重新聚合新的 store 的 state
        // 该为单分派  当 dispatch 完结 store 的 state 产生扭转的时候
        //UI 容器组件(StoreProvider,Relax) 会收到告诉从新 re-render UI
        this.store.dispatch('update')
    }
//  show multiple dispatch in a transaction  在事务中显示多个分派
    save = () =>{
        // 事务分派
        // 很多场景下  计算应该是原子类型的  咱们想一想 dispatch 完结才告诉 UI 去 re-render
        // 这个时候咱们就能够开启事务管制
        // transaction  会返回值来判断在 dispatch  过程中有没有产生谬误
        // 如果产生谬误  数据会主动回滚到上一次的状态  防止脏数据
        // 咱们也能够指定  自定义的回滚解决
        // this.transaction(()=>{/* 失常逻辑 */},()=>{/* 自定义的回滚函数 */})
        this.store.transaction(()=>{this.store.dispatch('loading:end')
            // 这个中央能够失去上一次的 dispatch 之后的后果
            // 如:const loading = this.state().get('loading')
            this.store.dispatch('init:user',{id:1,name:'plume2'})
            this.store.dispatch('save')
        })
    }
}


class AppStore extends Store{
//   聚合 Actor
//   通过 reduce 各个 actor 的 defaultState
// 聚合出 store 的 state 作为 source data
bindActor(){
    //plume2  间接传递 Actor 的 class
    return [LoadingActor,UserActor,TodoActor]
}
bindViewAction(){
    return{AppViewAction}
}
}

Store public-API

// 绑定须要聚合的 Actor
bindActor(): Array<Actor | typeof Actor>

bindViewAction(): IViewActionMapper

// 事务管制 dispatch
// dispatch: 失常逻辑
// rollBack: 自定义回滚逻辑  默认是主动回滚到上一次的状态
// 返回是否产生回滚

transaction(dispatch:Dispatch,rollBack:RollBack):boolean;

// 计算 QL

bigQuery(ql:QueryLang):any

// 以后 store 聚合的状态
state():IMap;

// 定义 store 状态更新告诉
subscribe(cb:Handler):void;

// 勾销订阅
unsubscribe(cb:Handler):void;

StoreProvider

StoreProvider 容器组件连接咱们的 React 组件和 AppStore。向 React 组件提供数据源

在 StoreProvider 中的次要工作是:
1 初始化咱们的 AppStore
2 将 AppStore 的对象绑定到 React 组件的上下文
3 Relay 就是通过上下文取的 store 对象
4 监听 Store 的 state 变动

情谊提醒:咱们还提供了 debug 模式

开启 debug 模式 咱们就能够对数据进行全链路跟踪

跟踪 store 的 dispatch actor 的解决 relax 对 QL 的计算等

import React, {Component} from 'react'
import {StoreProvider} from 'iflux2'
import AppStore from './store'

//enable debug
@StoreProvider(AppStore,{debug:true})
class ShoppingCart extends Component{render(){
        return(
            <Scene>
                <HeaderContainer/>
                <ShoppingCart/>
                <BottomToolBarContainer/>
            </Scene>
        )
    }
}

Relax

Relax 是 plume2 中十分重要的容器组件 相似 Spring 容器的依赖注入一样
外围性能会依据子组件的 relaxProps 中申明的数据,
通过智能计算属性的值 而后作为 this.props.relaxProps 透传给子组件

以此来解决 React 的 props 层层透传的 verbose 的问题

计算的规定
1 store 的 state 的值,间接给出值 得 immutable 的门路, 如 count:’count’,todoText:[‘todo’,1,’text’]
2 store 的 method 间接和 method 同名就 ok 如:destroy:noop, 咱们更心愿通过 ActionCreator 来独自解决 UI 的 side effect
3 如果属性是 ’viewAction’ 间接注入 store 中绑定的 ViewAction
4 如果属性是 QL 注入 QL 计算之后的后果 如果 PQL 会主动绑定 store 的上下文

@Relax
export default class Footer extends React.Component{
    static relaxProps = {
        changeFilter:noop,
        clearCompleted:noop,
        count:countQL,
        loadingPQL:loadingPQL,
        filterStatus:'filterStataus',
        viewAction:'viewAction'
    }
    render(){
        const{
            changeFilter,
            clearCompleted,
            count,
            filterStataus,
            viewAction
        } = this.props.relaxProps
    }
    //...
}

QL/PQL

为什么咱们须要一个 QL
1 咱们把 store state 看成 source data, 因为 UI 展现的数据,可能须要依据咱们的源数据进行组合
2 咱们须要 UI 的数据具备 reactive 的能力 当 source data 变动的时候 @Relax 会去从新计算咱们的 QL
3 命令式的编程手动的准确的解决数据之间的依赖和更新 Reactive 会主动解决数据的依赖 然而同一个 QL 可能会被执行屡次 造成计算上的节约
不过不须要放心 QL 反对 cache 确保 path 对应的数据没有变动的时候 QL 不会反复计算

QL = Query Lang
自定义查问语法 数据的源头是 store 的 state 返回的数据

Syntax QL(displayName,[string|array|QL…RelaxContainer,fn])

displayName, 次要是帮忙咱们在 debug 状态更好的日志跟踪

string array QL:string array 都是 immutable 的 get 的 path,QL 其余的 QL(反对无线嵌套)

fn: 可计算状态的回调函数 bigQuery 会获得所有的所有的数组中的 path 对应的值 作为参数传递给 fn


// 返回:{
//     id:1,
//     name:'iflux2',
//     address:{
//         city:'南京'
//     }
// }

store.state()

//QL 计算的后果值是 'iflux2 南京'
const helloQL = QL('helloQL',[
    'name',
    ['address','city'],
    (name,city)=>`${name}${city}`
])

Store.bigQuery(helloQL)
退出移动版