## 简介

> 用于组织react代码。分离数据，操作逻辑，和页面展示。

> 通过app.bindAction 和 app.bindModel  app.render   将组件，数据model，和行为逻辑进行结合

> 在组件内，通过props访问自定义模型名称，访问模型内定义的数据，通过props.action.逻辑名称，访问行为逻辑示例

> 通过 props.models 访问模型实例

> 在action里，通过this.actions 访问app内其他action，

> 通过 this.models 访问app绑定的model

### 一、数据

通过class定义一个数据，并且通过createStore，创建数据模型实例。class内有几个必须属性：

| 名称 | 说明 ｜
|-----|------|
| name | 表示这个数据模型的名字，之后都需要通过这个名字来进行数据的引用与修改 |
| data | 数据结构与初始化，定义数据结构和初始化最初数据 |

数据模型有几个默认方法：

- set：参数为一个或者两个，并且修改会触发两个事件，一个是change事件，另一个是change:\[key\]事件,key为当前更新的属性名称
    - 当参数是一个的时候，参数必须是一个对象，对象内为需要更新的数据和属性。且属性如果带‘.’符号，会递归数据找到需要更新的数据。例如 set({'a.b.c': '9'}')
    - 当参数是两个的时候，第一个参数是更新的key，第二个参数是更新的值

- get：接受一个参数，参数可以是一个字符串和一个数组
    - 参数为字符串的时候，参数作为属性名，返回该属性值
    - 参数为数组的时候，数组作为属性名数组，返回与数组顺序相同的属性值

- getType：返回数据类型，通过Object.prototype.toString.call实现

- has：接受一个字符串作为参数，判断数据内该属性值，是否为undefined或者为null，是返回false，不是返回true

- deepClone：接受最多一个对象作为参数，进行深拷贝，如果不传参数，则默认拷贝data属性，返回拷贝后的值

- previous：接受最多一个字符串作为参数，返回上一次修改的值，如果不传参数，会返回上一次修改的整个对象

- on: 接受两个参数，订阅事件，第一个参数为事件名称，第二个参数为回调函数

- off：取消订阅

- trigger：触发事件

model示例
```js
// ./demo/model.js
export default class {
    name = 'm1'
    data = {
        name: '姓名不重要'
    }
    testName() {
        alert(this.name);
    }
}
```

action里调用model示例
```js
// ./demo/action.js
export default class {
    changeName() {
        this.models.m1.set({
            name: '明天在来'
        });
    }

    didMount() {
        setTimeout(() => {
            this.changeName();
            this.models.m1.testName();
        }, 6000);


        console.log(this.models.m1.get('name'));
    }
}
```

组件里使用model内定义的数据示例
```js
// ./demo/Home.js
import React from 'react';
import {render, createStore} from '../src/frame';
import ChildPage from './Child';
import Action1 from './action';

const Home = render({
    actions: {
        action1: Action1,
    },
    models: ['m1']
})(({props, state, action}) => {

    const {m1} = props;

    return (
        <div>
            {m1.name}
            <ChildPage />
        </div>
    );
});


export default Home
```

### 二、行为逻辑


类默认的属性

- models：action通过这个属性调用数据模型的方法，models是个对象，存储的是所有创建的数据模型实例。

- actions：同组件引用的其他action，是个对象，属性为组件绑定action的时候指定的属性

- $instance：可以通过这个属性，拿到引用该类的组件实例

静态属性

- extends：接收一个数组，数组内是该类需要继承的其他父类，且父类也可以有extends属性，以实现多重继承

默认方法

- setState：同组件的setState

action示例
```js
// ./demo/action.js
import Action3 from './action3';

export default class {

    static extends = [Action3]
    
    changeName() {
        this.models.m1.set({
            name: '明天在来'
        });
    }

   
}
```

### 三、绑定

生成全局app进行绑定，绑定方法参数key是访问句柄，从组件里可以访问到

```js
import App from 'ader/lib/react-mlc';
import Action from './Action';
import Model from './Model';

let app = new App();

app.bindModel({
    pageM: Model
});

app.bindAction({
    pageA: Action
});

```

### 四、渲染API

render函数，是连接数据和逻辑的关键方法。render函数被调用两次，第一次调用传入配置参数。第二次调用传入一个函数，该函数拥有一个对象作为参数，对象内有props，state，action三个属性，并且返回一个组件。

配置参数：

- actions：对象，配置action，key为后续调用对应action的名称

- models：数组，该组件需要用到的数据模型名称，注意在配置model之前需要确保它被createStore调用过。
 > 注意models在这里只跟组件绑定，与action无关，任意action都可以拿到所有的models。

- state：为该组件定义的state值


render方法示例
```js
// ./demo/Child.js
import React from 'react';
import {render, createStore} from '../src/frame';
import Action2 from './action2';
import Model2 from './model2';
createStore([Model2]);

const Child = render({
    actions: {
        action2: Action2
    },
    models: ['m2']
})(({props, state, action}) => {
    const {m2} = props;
    console.log(props);

    return (
        <div>
            {m2.childName}
        </div>
    );
});

export default Child;
```

### 四、主要API

- render：调用两次，第一次传入配置参数，第二次传入一个返回jsx的函数。render函数返回一个组件

- createStore：接受一个数组，数组元素为定义的Model类。


> 注：demo用的babel配置 
{
    presets: ['@babel/env', '@babel/react'],
    plugins: [
        'transform-class-properties'
    ]
}