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

redux-watchman

v1.1.1

Published

redux middleware

Downloads

2

Readme

redux-watchman

redux-watchman 是一个基于async + await用于管理异步数据流的redux中间件。api的设计灵感来源于redux-saga,但是他:

  • 轻便 —— 经过转义压缩后仅 3KB
  • 实用 —— 根据saga常用的api进行设计,在async + await 普及的今天,它能带来不一样的开发体验。
  • 简易 —— 如果您是saga的用户,且熟悉async+await语法那可以说是0学习成本,如果您是新手,简易的demo也能让你快速入手。
  • 可靠 —— 作者已将其用在公司若干个项目中,线上稳定运行。
  • 友好 —— redux-watchman使用 typescript 编写,且配置好 d.ts文件,能提供良好的编码提示。

如果你是 redux 的使用者,且在项目中习惯使用异步流管理数据交互,redux-watchman将会是你不错的选择。

开始

安装

$ npm install redux-watchman -S

或者你可以在githubclone下本项目然后:

$ npm i
$ npm run build:umd

通过script标签引入umd文件夹下的js文件。

使用示例

下面我们通过一个通讯录的部分crud来描述:

// reducer.js

// 设置通讯录列表
const set = (state,action)=>{
  return {
    contacts: action.payload
  }
}
// 新增/修改联系人
const edit = (state,action)=>{
  const contacts = state.contacts;
  const index = contacts.findIndex(contact=>contact.id === action.payload);
  if(index !== -1) {
    contacts.splice(index, 1, action.payload);
    return {
      contacts: [...contacts]
    }
  }
  return {
    contacts: [...contacts, action.payload]
  }
}
// ... 省略del
const reducer = (state,action)=>{
  const handler = {
    set,
    edit,
    del
  }
  if(handler[action.type]) return handler[action.type](state,action);
  return state
}
export default reducer;
// watchman.js
import { all, put, select, take, takeEvery } from 'redux-watchman';
// 用来模拟异步请求
const requestMock = function(data){
  return Promise.resolve(data);
}
// 用来生成单个人员
const contactFactory = function(name = 'lee', phone = '123'){
  return {
    id: Math.random() * 100,
    name,
    phone
  }
}
// 下面开始定义监听的各个action
// 查询联系人
const query = async function(){
  // 仅监听一次type为query的action。因为大列表的数据一般只需要查询一次
  await take('query');
	
  // 模拟异步过程
  const mock = [
    contactFactory('lee', '123'),
    contactFactory('zhao', '123')
  ]
  const payload = await requestMock(mock);
  // 往reducer上抛
  await put({ type: 'set', payload})
}
// 新增/修改联系人
const edit = async function(){
  // 多次监听type为editAsync的action,因为这个会频繁操作,监听回调会接收当前action作为参数
  await takeEvery('editAsync', async function(action){
    let mockData = action.payload;
    // 根据id判断新增还是修改
    if(!action.payload.id){
      mockData = {...mockData, id: Math.random()}
    }
    // 模拟异步
    const payload = await requestMock(mockData);
    // 同上
    await put({ type: 'edit', payload})
  })
}
// 异步删除操作
const del = async function(){
  await takeEvery('delAsync', async function(action){
    if(!action.payload.id)return
    const result = await requestMock(true);
    if(result)await put({ type: 'del', payload: action.payload.id})
  })
}
// 删除最后一个
const pop = async function(){
  await takeEvery('popAsync', async function(action){
    // 先找到最后一个然后删除
    const contacts = await select(function(state){return state.contacts});
    const last = contacts[contacts.length - 1];
    const result = await requestMock(true);
    if(result)await put({ type: 'del', payload: last.id})
  })
}

// 把响应的方法整合,通过一个接口导出
const root = async function(){
  await all([ query, edit, del, pop ])
}

export default root;

import { createStore, applyMiddleware } from 'redux';
import { createWatchman } from 'redux-watchman';
import reducer from './reducer';
import root from './watchman';
// 先创建一个watchman
const watchman = createWatchman();
const store = createStore(
  reducer,
  {
    contacts: []
  },
  applyMiddleware(
    watchman.watchmanMiddleware // 加入middleware
  )
)
// run之前定义的所有方法
watchman.run(root);


// 接下来描述这样一个过程
// 定义一个数据打印方法,方便查看每个dispatch后的数据变化。
const withStoreShow = (f)=>{
  f();
  return new Promise(resolve=>{
    setTimeout(()=>{
      console.log('state');
      console.log(JSON.stringify(store.getState()));
      console.log('-----------------------')
      resolve()
    }, 200);
  })
}

const run = async function(){
  // query
  await withStoreShow(()=>{
    console.log('query');
    store.dispatch({ type: 'query' })
  });
  // 新增
  await withStoreShow(()=>{
    console.log('editAsync');
    store.dispatch({ type: 'editAsync', payload: {name: 'wang', phone: '333'}})
  });
  // 修改
  await withStoreShow(()=>{
    console.log('editAsync');
    const state = store.getState();
    store.dispatch({ type: 'editAsync', payload: {id: state.contacts[0].id, name: 'll', phone: '773'}})
  });

  // 删除
  await withStoreShow(()=>{
    console.log('delAsync');
    const state = store.getState();
    store.dispatch({ type: 'delAsync', payload: state.contacts[0].id})
  });
  // 删除最后一个
  await withStoreShow(()=>{
    console.log('pop');
    store.dispatch({ type: 'popAsync' })
  });
}

run();

文档

以下均为函数

| 名称 | 参数 | 描述 | | :------------: | :---------------------------: | :----------------------------------------------------------- | | take | string | 接收一个字符串,作为参数,仅监听一次type值为该字符串的action。返回一个promise,当该type值的actiondispatch时,promise变为resolved状态,Promise值为当前action | | takeEvery | string, asyncFunction | 多次take;当监听到对应action时,调用传入的async方法,在当前async方法返回的promise状态变更之前,再次dispatch相同typeaction,方法不会响应。返回一个状态永远为penddingPromise。 | | put | action | 可以简单的理解为store.dispath,返回一个PromisePromise值为当前action | | select | (state)=>{} | select接收一个函数ff能拿到当前state作为参数,select返回一个Promise,该Promise的值为函数f的返回值。 | | all | asyncFunction[] | 可以简单的理解为Promise.all | | createWatchman | / | 不需要传参,调用后返回{ run, watchmanMiddleware },需要将watchmanMiddleware加入到redux middleware中并初始化reduxrun接收一个asyncFunction,用于启动上面定义的effect。 |

License

MIT