node package manager
It’s your turn. Help us improve JavaScript. Take the 2017 JavaScript Ecosystem Survey »

remex

Remex

Remex is a practical framework for Javascript apps without any buy-in from developers.

It provides useful utilities such as Node to help you wrap raw data into traditional style model. On top of these utilities, your application code will be clean, intuitive and easy to test. By taking cues from functional programming, modern features like time traveling debugger are also available.

You can use Remex together with React, or with any other view library.

Quick Start

Use Remex is easy, and data flow are simple. Application models is managed by Remex. Component subscribe model from Remex. The only way to change model data or call model method is to fire a event using a string-based event bus provided by Remex, and then operate the model in the event listener. When model data changes, Remex will automatically notify components which subscribed the changed model.

It only take a few minutes to build a real Remex project with React, let's get start.

Installation

We use antd-init as scaffold. antd-init integrates webpack and babel to compile and serve the project, so you can focus on your code.

Initialize the project:

npm install antd-init -g
mkdir roof-demo && cd roof-demo
antd-init

Once initialized, your project directory structure looks something like this:

├── index.html        
├── package.json      
└── src               //your app source code
    ├── common
    │   └── lib.js
    ├── component
    │   ├── App.jsx   //your root component
    │   └── User.jsx  
    ├── data          //store your model
    │   └── user.js
    ├── entry         //your entry file, created by antd-init
    │   └── index.jsx
    └── event         //store your event listeners
        └── user.js

Note that directory data and event should be create by yourself manually. We will use these two directory to store model and event listeners. For other missing files we will create them lately in this guide.

Install Remex and start the server:

npm install roof --save
npm run dev

Now your app is running, visit http://127.0.0.1:8000.

Create Model

Creating a Model is extremely easy:

// import base class
import {Node} from 'remex'           
 
// Use base class to create your own model class
const User = Node.createClass({
    // define model method
    getFullName(){
        // Use base class's get method to get property
        return this.get('name') + ' ' + this.get('family')
    }
})
 
// export a function to return you model instance to Remex
export default function UserFactory(){
    return new User({
        name: 'Jane',
        family : 'Doe',
        age : 22
    })
}   

Use Model

First, we bind our model to app root component using Remex API createRootContainer:

/src/component/App.jsx

import React from 'react';
import Remex from 'Remex';
import 'Remex/addon/react/container';
import User from './User';
import UserFactory from '../data/user';
 
const App = React.createClass({
 render(){
   return <div>
     <div>Hello :</div>
     <User />
   </div>
 }
})
 
 
const Container = Roof.createRootContainer(App,{
    models : {
        globalUser: UserFactory
    }
})
 
export default Container;

We gave the name globalUser to our first model in the code, any descendant component can subscribe the data by the same name, now let's subscribe it in a child component User:

/src/Component/User.jsx

import React from 'react';
import Remex from 'remex';
 
const User = React.createClass({
  render(){
    return <div>
      <div>{this.props.user.getFullName()} {this.props.user.get('age')}</div>
    </div>
  }
})
 
const UserContainer = Remex.createContainer( User, {
    subscribe : {
     user : 'globalUser'
   }
}) 
  
export default UserContainer;

Refresh your browser, your app should be showing the user's name and age.

Fire a event

By default, Remex will pass a event bus instance as property bus to your component which has been wrapped by Remex.createContainer, so just use this bus instance to fire a event. Say if we want to increase the user's age, just change the component like:

/src/Component/User.jsx

const User = React.createClass({
    increaseUserAge(){
        this.props.bus.fire('user.increaseAge', 2)
    }
   render(){
     return (
     <div>
       <div>{this.props.user.getFullName()} {this.props.user.get('age')}</div>
       <button onClick={this.increaseUserAge}>add 2 to user's age</button>
     </div>
     )
  }
})

Listen to event

Finally, let's handle the event we just fired. First create listener file and write the listener code:

/src/event/user.js

// export a function 
export default function UserListenerFactory( models ){
    return {
        'user.increaseAge' : function increaseUserAge( ageToIncrease ){
            const user = models.get('globalUser')
            user.set('age', this.get('age') + ageToIncrease )
        }
    }
}

Listener finished. Now tell Remex to attach your listeners when create root container, add a few lines to App.jsx

/src/component/App.jsx

 
// import listener file
import UserEventFactory from '../event/user';
 
// change container code, add event listner
const Container = Roof.createRootContainer(App,{
    models : {
        globalUser: UserFactory
    },
    events : {
        userListeners : UserEventFactory
    }
})

That's it, now the event you fired can be properly handled. Here you may have a question: Why use a key-value map to define events? What does the key userListeners means? The key userListeners is the group name of our listeners. Actually every listener in Remex will be given a uniq name follow the pattern of [group name].[function name]. For example, our first listener in the code above will be named userListeners.increaseUserAge. The uniq name will be used when we want to control the fire sequence of listeners.

If you follow the quick start guide step by step, you are already capable of using Remex in your own project. For more example and tutorial, visit our tutorial document or checkout example code in the repository. For those who are already familiar with Flux-like frameworks you may want to know why we use model and event or How we hanle AJAX and other async events

For more details, just Read on

princepals:

  • how to use async actions
  • how to use action with bad backend APIs

why modal and event-bus:

  • modal based architecture is easy to integrate with backend.
  • event bus is more practical.

todo:

  • data 改成 models
  • 改 api 为高阶组件的写法
  • dev tools 参考 redux
  • roof-zeroql 开源版
  • API