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

refer

v0.0.18

Published

redux-like library for handling global state on functional style

Downloads

41

Readme

refer

redux-like library for handling global state on functional style

refer 介绍

refer 是一个状态管理库,受到了 redux 的启发和影响,源码结构以及 API 也高度相似。所不同的是,refer 体积更小,概念更少,灵活性更强。

通常来说,用户只需要用到 createStore 一个 api。去掉了 redux 的 combineReducers、bindActionCreators 以及 applyMiddleware 等动作。

在深入了解 refer 之后,你将发现,那些概念是不必要的。每个动作都是一个 handler,所谓的 middleware、actionCreator 和 reducer 等, 只是一串相继执行的 handlers 的不同阶段而已。

引入 refer

npm install refer

refer 遵循 UMD 模块规范。在没有模块化环境时,将输出到全局变量 Refer

script 标签引入

<script src="refer.min.js"></script>
<script>console.log(Refer)</script>

AMD 模块加载

define(['refer'], function(Refer) {
	console.log(Refer)
})

commonjs

var Refer = require('refer')
console.log(Refer)

ES2015

import Refer from 'refer'
console.log(Refer)

理解 refer

refer 跟 redux 一样,崇尚(pure function)纯函数。

什么是 refer handler?

refer handler 是接受一个参数并返回一个值的普通函数,或者这类函数所组成的数组,甚至可以任意嵌套。

// 返回一个数的后继
let succ = n => n + 1
let double = x => x * 2
let succ_double = [succ, double]
let handler1 = [succ, [double, succ], double]

什么是 refer handlers?

refer handlers 是一个 key-value 对象。value 为 refer handler, key 则是其字符串代号。

let handlers = {
	succ: n => n + 1,
	double: x => x * 2,
	succ_double: ['succ', 'double'],
	key1: 'succ',
	key2: ['succ', [x => x - 1, 'key1']]
}

refer handlers 的 key 可以作为 value,或者 value 数组里的一项,增加复用能力。

你已经掌握了 refer 的一半。

refercreateStore 函数,接受两个参数: handlersinitialState,返回一个对象。

handlers 就是你刚才所掌握的,单参数函数的排列组合与命名。initialState 则默认为空对象{}

createStore 返回的对象拥有几个属性。

getState 函数

返回当前 state 数据,默认是 initialState,除非 state 被改变。

subscribe(callback) 函数

订阅 state 变化的消息,callback 被调用时不接受任何参数。该订阅函数将返回一个解除订阅的函数。

replaceState(nextState, silent) 函数

用 nextState 替换当前的 state,如果 silent 为 true,则不触发消息发布

dispatch(key, value) 函数

接受两个参数 key 与 value,key 匹配出 refer handlers对象里的 handler,然后以 pipe 的形式依次执行里面的函数。

第一个函数接收的参数为 value,第二个函数接收的参数为第一个函数的返回值,以此类推。

注意:最后一个函数必须返回一个更新 state 的函数。dispatch 方法在同步 handler 时返回更新后的 state

let handlers = {
	add: [n => n * 2, n => n / 2, n => state => state + n],
	reduce: n => state => state - n
}
// initialState 不要求必须是对象,可以是任意值
let store = createStore(handlers, 0)
store.dispatch('add', 10) // 返回最新的 state: 10
store.dispatch('reduce', 100) // 返回最新的 state: 99

handler 里的任意函数都可以返回一个 promise,它后面的函数将会在 promise.then 之后继续进行。不需要像redux-promise这类中间件的支持,refer 天生支持异步。

如果有函数返回 promise,dispatch 方法返回的也是 promise。

注意:在两种情况下,dispatch 返回的是 promise 对象

  • handler 里的某个函数返回 promise
  • handler 里任意函数抛出错误,这个错误将以 Promise.reject(error) 形式返回。
let handlers = {
	add: [n => n * 2, n => n / 2, n => state => state + n],
	reduce: n => state => state - n,
	asyncAdd: n => state => Promise.resolve(state + n),
	errorAdd: n => state => { throw new Error('I am error')}
}
let store = createStore(handlers, 0)

store.dispatch('add', 10) // 返回最新的 state: 10

// 异步返回最新的 state
store.dispatch('asyncAdd', 10)
	.then(state => console.log(state)) // 20
store.dispatch('errorAdd', 100)
	.catch(error => console.log(error.message)) // I am error

由于 dispatch 函数在同步和异步两种情况下都可能返回 promise。可以用下面列举的方式,兼顾成功与失败两种情形。

  • 确定 handler 中所有函数都是同步执行的情况

    • 判断 dispatch 的返回值是不是 thenable 对象,如果是,则说明存在错误
  • handler 里的函数有可能同步也有可能异步的情况

    • 用 Promise.resolve(dispatch(key, value)).then(success).catch(fail) 处理
  • handler 里存在异步情况

    • dispatch(key, value).then(success).catch(fail)

actions 对象

actions 对象的 key 跟 refer handlers 完全一致,它的值则是一个函数: value => dispatch(key, value)。

因此,你再需要使用 bindActionCreators 函数手动构造一个 actions。refer 已经提供好了。

let handlers = {
	add: [n => n * 2, n => n / 2, n => state => state + n],
	reduce: n => state => state - n,
	asyncAdd: n => state => Promise.resolve(state + n),
	errorAdd: n => state => { throw new Error('I am error')}
}
let store = createStore(handlers, 0)
let { add, asyncAdd, errorAdd } = store.actions

add(10) // 返回最新的 state: 10

// 异步返回最新的 state
asyncAdd(10)
	.then(state => console.log(state)) // 20
errorAdd(100)
	.catch(error => console.log(error.message)) // I am error

你已经掌握了 refer 的八成

refer 的理念非常简单,就是依次执行一组函数,根据 key 来调节各组函数的执行时机,根据各个函数是否返回 promise 来决定下一个函数是同步还是异步执行。

refer 的高级用法

如何写中间件?

redux 的中间件是一个函数,而 refer 的中间件则是一个可复用的 refer handlers

createStore(handlers, initialState) 的 handlers 参数,支持数组类型,也就是说,你可以把多个 handlers 打包成一个数组传入。

createStore([handlers1, handlers2, handlers3])

各个 handlers 的同名 handler,会按照 handlers 在数组里的索引顺序拼接起来。

// 多个 handlers 将拼接成一个更大的 handlers 对象
{
	[key]: [handler1.key, handler2.key, handler3.key]
}

也就是说,handler2 的某个 key 所对应的 handler 的第一个函数,其接收的参数将收到 handlers1 的影响,如果它没有同名的 handler,则接收 value,如果它有,则接受 handers1[key] 所返回的值。

值得注意的是,每个 handlers 的 key ,其代号意义,只在该 handlers 对象中有效。不能在 handlersA 中使用它不存在,但 handlersB 中存在的 handler 代号。

了解 refer 的生命周期钩子

handlers 的 key 没有限制。但 refer 选取了几个特殊的 key 值,它们不参与更新 state。

handlers[lifeCycleHook] 将在 dispatch 函数执行的各个特定阶段依次被调用,它们会被传入相应一个对象参数 data

  • data.key: dispatch 的 key 参数
  • data.value: dispatch 的 value 参数
  • data.currentState: 当前的 state
  • data.nextState: 下一个 state
  • data.error: dispatch 出错时的错误信息

@SHOULD_DISPATCH

在 dispatch 执行时,最先被调用的生命周期函数,如果它返回 false,将终止此次 dispatch。该函数的 data 参数只有 key 、value、 currentState 三个属性。

@DISPATCH

紧接着 @SHOULD_DISPATCH 之后,该生命周期函数被调用,data 参数的属性与 @SHOULD_DISPATCH 相同。

@SHOULD_UPDATE

在 nextState 存在时被调用,data 参数的属性有 key、 value、 currentState 与 nextState 四个,如果它返回 false,将终止更新 state。

@WILL_UPDATE

在 currentState 即将被 nextState 所替换前调用,data 参数与 @SHOULD_UPDATE 相同。

@DID_UPDATE

在 currentState 被 nextState 所替换后调用,data 参数与 @SHOULD_UPDATE 相同。注意:此时的 data.nextState 才是跟 store.getState() 返回值相等。

@SYNC

在 currentState 以同步方式被更新后调用,参数与 @SHOULD_UPDATE 相同。

@ASYNC_START

在 currentState 以异步方式更新开始阶段被调用,data 参数为 key、value、currentState 与 nextState,其中 nextState 为 promise 对象。

@ASYNC_END

在 currentState 以异步方式更新结束时调用,data 参数为 key、value、currentState 与 (nextState || error )。当异步更新成功时,nextState 属性存在,error 不存在;当异步更新存在错误时,nextState 不存在,error 存在。

@THROW_ERROR

当 dispatch 中存在错误时调用,该生命周期函数将接收一个 error 参数对象。该函数的返回值将被 Promise.reject 包裹,作为 dispatch 的返回值。

也就是说,用户可以通过 @THROW_ERROR 钩子,控制 dispatch 出错时返回的 promise 对象携带的错误信息是什么。用户可以 dispatch(key, value).catch(fail) 进行处理。

注意:dispatch 时的所有错误信息都会进入这个生命周期钩子函数,包括 handler 里的函数故意抛出的错误,或者返回 Promise.reject。

了解 refer 的生态

refer 还比较新,目前并没有社区生态,希望你能加入。

refer-logger 是根据 refer 生命周期钩子写的日志中间件。

import createLogger from 'refer-logger'
let logger = createLogger({
	scope: 'scopeName',
	debug: true
})

createLogger 接受一个对象参数,scope 属性默认为 Root, debug 为 true 时则在 @THROW_ERROR 钩子中抛出错误(因为部分浏览器不显示 promise 里包含的错误信息)。

当 action 被调用时,控制台将输出 key、value、nextState、currentState 以及此 action 的发生时间,消耗时长等信息。

refer-dom 是 refer 与 virtual-dom 结合的产物,它完整模拟了 react 的 component api,可以无缝跑起 react component 代码,只需要将 react 依赖指向 refer-dom 即可。

refer-dom 的 component api 是 react component 的超集,你可以在组件的 getHandlers 方法返回自定义的 handlers,然后用组件的 actions 属性里的函数来更新组件的 state。setState 方法在 refer-dom 里,只是更新 state 的其中一个 action 而已。

基于 refer 是如此简单易用,相信你能发挥出更大的威力。一起来构建 refer 生态吧。