npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

page-control

v1.0.0

Published

page control

Downloads

10

Readme

rx-hub

使用数据板, 将数据当作 水流一样,集中管理和监视 数据流

数据从数据源流出(比如一个点击事件流),在不同的水管中流动变换,最终流向目的地(比如界面UI)。

依赖RxJS 5

Issues

  • 依赖RxJS 5, rx-hub安装包不包含rxjs, 需要单独安装npm install [email protected] -S
  • 兼容性:和RxJs一样,支持ie9+和当前的主流浏览器,具体请查看RxJS的兼容性。

Features

  • 使用RxJS数据流,具有RxJS的特性。
  • 数据集中通过数据板处理,数据流清晰,配合中间件middleware, 监控每一次数据流动变换。
  • 提供内置数据仓库Store
  • 单向数据流。
  • 适用于绝大多数框架,同一份数据可以同时用于原生js、vue、react等页面……

Overview

rx-hub data flow.

概念

  • Hub: 数据板,用来安装各种管道Pipe,需要使用数据、或者改变数据的时候,直接和数据板打交道就行。

  • Converter: 换流器,数据变换,接受一个数据,然后根据一定规则变换成另一个数据流。

  • Pipe: 管道,数据管道,一个入口,一个出口,流入旧数据,经过Converter变换,流出新数据。

  • Store: 数据池,存储数据。

  • Middleware: 中间件,特殊的Converter, 挂载在管道的入口和出口,用来调试、打印日志,或者统一变换数据。

  • Observable: 可观察的数据流,RxJS中的主要概念,也是rx-hub中的数据流,可以订阅。

Reference directory structure

|
|---- `style`
|---- `entry`
|---- `lib`
|---- `data`: 数据管理
| |---- `converters`
  | |---- `server`
  | | |---- `user.js`
  | |
  | |---- `store.js`
  |
  |---- `hubs`
  | |---- `main.js`
  |
  |---- `stores`
  | |---- `main.js`
    |---- `modules`
      |- `user.js`

Getting started

install

# install rx-hub
npm install rx-hub -S

# install rxjs, rx-hub have a peerDependencies of [email protected]
npm install [email protected] -S

# 使用编译后的模块
import {Hub, Store, logMiddleware} from 'data-hub';

# 或者使用es6模块:
import Hub from 'data-hub/src/hub';
import Store from 'data-hub/src/store';
import logMiddleware from 'data-hub/src/middleware/log';

定义Converter

每个Converter是一个函数,接受一个数据payload, 返回一个新的Observable对象。

// converters/server/user.js
import axios from 'axios';
import Rx from 'rxjs';

export let userDel = (userId) => {
  let promise = new Promise((resolve, reject) => {
    setTimeout(() => resolve(userId), 1000);
  });
  return Rx.Observable.from(promise);
};

export let userAdd = (user) => {
  // let  promsie = axios({
  //   url: 'http://www.baidu.com',
  //   method: 'post',
  //   data: data
  // }).then(response => {
  //   return response.data
  // });

  let promise = new Promise((resolve, reject) => {
    setTimeout(() => resolve(user), 1000);
  });
  return Rx.Observable.from(promise);
};
// converters/store.js
import {BehaviorSubject, Observable} from 'rxjs';
import mainStore from '../stores/main';

// 获取最新state
export let getState = () => {
  let state = mainStore.getState();
  let subject = new BehaviorSubject(state);
  mainStore.subscribe(subject);
  return subject;
};

// 提交更改
export let commit = ({mutation, payload}) => {
  mainStore.commit(mutation, payload);
  return Observable.of(payload);
};

定义一个Store.

Store用来长时间存储数据,类似现实生活中的水池Store可以包含子模块modules, 每个子模块都是一个Store实例。

// sotres/main.js
import {Store} from 'data-hub';
import user from './modules/user';

export default new Store({
  initialState: {
    user: {
      username: 'season.chen'
    }
  },
  modules: {
    user, // 用户子模块
  }
});
// stores/modules/user.js
import {Store} from 'data-hub';

export default new Store({
  initialState: {
    list: []
  },

  mutations: {
    add(user, state) {
      state.list.push(user);
    }
  }
});

初始一个Hub实例。

hub是一个数据板,sotre, ui, server 等等数据交换都流经hub。在数据板上添加各种管道Pipe, 可以单个添加和批量添加。

// hubs/main.js

import {Hub, logMiddleware} from 'data-hub';
import Rx from 'rxjs';
import mainStore from '../stores/main';
import * as userServerConverters from '../converters/server/user';
import * as storeConverters from '../converters/store';

const hub = new Hub({
  beforeMiddlewares: [logMiddleware],
  afterMiddlewares: [logMiddleware],
});

// actions
hub.addPipes('server.user', userServerConverters);

// server
hub.addPipes('store', storeConverters);

export default hub;

连接管道,拼接成数据的流动路线。

管道只提供数据转换的通道,最终我们要做的,就是讲这些管道组织起来,使数据从源头经过设定好的路线,流向目的地。

index.html:

<div class="app" id="app">
    <div class="topBar">
      user: username
    </div>

    <div class="filter">
      <input type="text" placeholder="关键字" name="filter" id="filter">
      <button type="button" name="button" id="search">
        添加
      </button>
    </div>

    <table id="table">
      <thead>
        <tr>
          <th>id</th>
          <th>用户名</th>
          <th>操作</th>
        </tr>
      </thead>
      <tbody>

      </tbody>
    </table>
  </div>

index.js:

import hub from '../data/hubs/main';
import {Observable} from 'rxjs';
import NProgress from 'nprogress';
import 'nprogress/nprogress.css';
import "../style/style.less";

let $app = document.getElementById('app');
let $filter = document.getElementById('filter');
let $btn = document.getElementById('search');
let $table = document.getElementById('table');

let userList = [];
let userListAfterFilter = userList;

function filter(list) {
  let filter = $filter.value.trim();
  return userList.filter(user => {
    return user.name.indexOf(filter) != -1;
  });
}

// rerender table
function updateTable() {
  let $rows = userListAfterFilter
    .map((user, i) => {
      return `
        <tr>
          <td>${user.id}</td>
          <td>${user.name}</td>
          <td>
            <button type="button" name="button" data-index="${i}">删除</button>
          </td>
        </tr>
      `;
    });

  // bind delete user
  $table.querySelector('tbody').innerHTML = $rows.join('');
  $table.querySelectorAll('tr > td > button').forEach(($btn, index) => {
    // delete
    Observable.fromEvent($btn, 'click')
      .pluck('target')
      .map(target => {
        let i = target.getAttribute('data-index');
        let u = userListAfterFilter[i];

        NProgress.start();

        return u.id;
      })
      .switchMap(hub.pipe('server.user.userDel'))
      .map(id => {
        return {
          mutation: 'user.delete',
          payload: id
        }
      })
      .concatMap(hub.pipe('store.commit'))
      .subscribe(() => {
        console.log('success')
        NProgress.done();
      }, (err) => {
        console.log(err);
        NProgress.done();
      });
  });
}

// watch state change
Observable.of({})
  .concatMap(hub.pipe('store.getState'))
  .subscribe((state) => {
    userList = state.user.list;
    userListAfterFilter = filter(userList);
    updateTable();
  });

// filter input
Observable.fromEvent($filter, 'input')
  .debounceTime(500)
  .subscribe(() => {
    userListAfterFilter = filter(userList);
    updateTable();
  });

// add new user
let addUserSubscription;
$btn.addEventListener('click', () => {
  // unsubscibe
  if (addUserSubscription) addUserSubscription.unsubscribe();

  let user = {
    id: Date.now(),
    name: 'user-' + Math.round(Math.random() * 1000000),
  }

  NProgress.start();

  addUserSubscription = Observable.of(user)
  .switchMap(hub.pipe('server.user.userAdd'))
  .map((user) => {
    return {
      mutation: 'user.add',
      payload: user
    }
  })
  .concatMap(hub.pipe('store.commit'))
  .subscribe(() => {
    console.log('success')
    NProgress.done();
  }, (err) => {
    console.log(err);
    NProgress.done();
  });
});

API

API文档.

run demo

已经为您提供了原生jsvuereact三个版本的demo,三个demo共用一份数据,你可以查看demos目录中的源码以了解更多细节。

git clone https://github.com/ccqgithub/rx-hub.git
cd rx-hub/demos
npm install
num run dev
  • 原生js: http://localhost:8181/index.html
  • vue: http://localhost:8181/vue.html
  • react: http://localhost:8181/index.html