-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #16 from filefoxper/3.1.2
v3.1.2
- Loading branch information
Showing
134 changed files
with
11,457 additions
and
2,863 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,14 @@ | ||
## v3.1.1 2020-12-17 | ||
|
||
[bug] 已修复 reducer.update 方法中当 state 为 undefined 时, | ||
外部 store state 与 agent state 不同步的问题。 | ||
* [bug] 已修复 reducer.update 方法中当 state 为 undefined 时, | ||
外部 store state 与 agent state 不同步的问题。 | ||
|
||
## v3.1.2 2021-02-28 | ||
|
||
* [bug] 使用常规 debounce 代码修复原`MiddleWares.takeDebounce`因事件堆积导致的不稳定问题。 | ||
* [bug] 修复了`globalConfig`在无法获取到`window,global,self`情况下报错的问题。 | ||
* [feature] 新增`nextExperience`下一版本体验特性,并在`env`中增加了相应开启配置项。 | ||
`MiddleWare`的覆盖优先级将在`nextExperience`环境中变更为:`useMiddleWare` -> `middleWare` -> `createAgentReducer`。 | ||
* [document] 更改了文档结构以方便分步阅读。 | ||
* [document] 新增了英文文档。 | ||
* [unit test] 根据文档变更,新增了中英文分离的单元测试案例。 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,132 @@ | ||
[![npm][npm-image]][npm-url] | ||
[![standard][standard-image]][standard-url] | ||
|
||
[npm-image]: https://img.shields.io/npm/v/agent-reducer.svg?style=flat-square | ||
[npm-url]: https://www.npmjs.com/package/agent-reducer | ||
[standard-image]: https://img.shields.io/badge/code%20style-standard-brightgreen.svg?style=flat-square | ||
[standard-url]: http://npm.im/standard | ||
|
||
# agent-reducer | ||
|
||
想要一个更简单的`reducer`?试试`agent-reducer`。 | ||
|
||
`agent-reducer`能将一个模型 ( class实例或object ) 转换成`reducer` function。这个模型被称为`OriginAgent`,它必须含有一个`state`属性,用来存储需要持续维护的数据,同时它可以包含若干个方法用来处理数据分流。这些方法的返回值被称为`next state`,它将会替换原来的`state`属性值,成为处理后模型的新`state`状态数据。你可以通过使用`MiddleWare`的方式,在`next state`成为新`state`之前,拦截它,并对`next state`进行再加工,丢弃等处理,从而影响最终的新`state`数据。你也可以使用`MiddleWare`做出方法控制效果,比如:debounce ... 等。 | ||
|
||
## 使用 | ||
|
||
### 对比经典reducer用法 | ||
```typescript | ||
import {OriginAgent} from "agent-reducer"; | ||
import {useReducer} from 'react'; | ||
import {useAgentReducer} from 'use-agent-reducer'; | ||
|
||
interface Action { | ||
type?: 'stepUp' | 'stepDown' | 'step' | 'sum', | ||
payload?: number[] | boolean | ||
} | ||
|
||
/** | ||
* 经典的reducer写法 | ||
* @param state | ||
* @param action | ||
*/ | ||
const countReducer = (state: number = 0, action: Action = {}): number => { | ||
switch (action.type) { | ||
case "stepDown": | ||
return state - 1; | ||
case "stepUp": | ||
return state + 1; | ||
case "step": | ||
return state + (action.payload ? 1 : -1); | ||
case "sum": | ||
return state + (Array.isArray(action.payload) ? | ||
action.payload : []).reduce((r, c): number => r + c, 0); | ||
default: | ||
return state; | ||
} | ||
} | ||
|
||
/** | ||
* agent-reducer 模型写法与 reducer 经典很接近, | ||
* 但因为使用 class 作为模型,所以在数据分流和处理入参方面更简单 | ||
*/ | ||
class CountAgent implements OriginAgent<number> { | ||
|
||
state = 0; | ||
|
||
stepUp = (): number => this.state + 1; | ||
|
||
stepDown = (): number => this.state - 1; | ||
|
||
step(isUp: boolean):number{ | ||
// 内部复用方法'stepUp','stepDown'不能直接产生next state | ||
// 这些方法并不会触发 state 的 dispatch 行为 | ||
return isUp ? this.stepUp() : this.stepDown(); | ||
} | ||
|
||
sum(...counts: number[]): number { | ||
return this.state + counts.reduce((r, c): number => r + c, 0); | ||
}; | ||
|
||
} | ||
|
||
// 经典 reducer | ||
const [ state, dispatch ] = useReducer(countReducer,0); | ||
|
||
const handleSum = (...additions:number[]) => { | ||
// 我们只能通过 dispatch 一个 action object 与 reducer 进行沟通 | ||
dispatch({type:'sum',payload:additions}); | ||
}; | ||
|
||
// agent-reducer | ||
const { state:agentState, stepUp } = useAgentReducer(CountAgent); | ||
|
||
// 通过模型获取的方法可以被直接调用,传参 | ||
// 方法中的关键词 this 已被 agent-reducer 绑定在模型上, | ||
// 所以可以通过赋值的方式把该方法赋给任意对象,而不用担心调用时 this 出错的问题 | ||
const handleAgentSum = stepUp; | ||
``` | ||
`agent-reducer`作为一个独立包不能直接用在类似`react`、`redux`系统中,我们需要构建系统接驳工具来衔接它。幸运的是我们可以找到[use-agent-reducer](https://www.npmjs.com/package/use-agent-reducer)、[use-redux-agent](https://www.npmjs.com/package/use-redux-agent)这些现存的接驳工具分别衔接`react`、`redux`系统。如果有兴趣你也可以学习如何编写一个衔接器让`agent-reducer`接入更多的系统。 | ||
|
||
#### 使用MiddleWare: | ||
|
||
```typescript | ||
import {MiddleWarePresets,createAgentReducer} from 'agent-reducer'; | ||
|
||
class CountAgent implements OriginAgent<number> { | ||
|
||
state = 0; | ||
|
||
stepUp = (): number => this.state + 1; | ||
|
||
stepDown = (): number => this.state - 1; | ||
|
||
step(isUp: boolean):number{ | ||
return isUp ? this.stepUp() : this.stepDown(); | ||
} | ||
// 如果希望使用promise resolve的数据作为下一个state, | ||
// 你需要使用 MiddleWare 系统 | ||
async sumByRequests(): number { | ||
const counts = await Promise.resolve([1,2,3]); | ||
return counts.reduce((r, c): number => r + c, 0); | ||
}; | ||
|
||
} | ||
|
||
//使用 MiddleWarePresets.takePromiseResolve() | ||
const {agent}=createAgentReducer(CountAgent,MiddleWarePresets.takePromiseResolve()); | ||
|
||
await agent.sumByRequests(); | ||
|
||
agent.state; // 6 | ||
|
||
``` | ||
`agent-reducer`提供了一套实用的`MiddleWare`系统,你可以从`MiddleWarePresets`或`MiddleWares`中挑选合适的`MiddleWare`使用,api:`middleWare`、`useMiddleWare`、`createAgentReducer`都为你提供了使用接口。当然如果有特殊需求,你也可以写一个自己的`MiddleWare`。 | ||
|
||
## 连接器 | ||
1. [use-agent-reducer](https://www.npmjs.com/package/use-agent-reducer) react hook,用来代替 `react useReducer`. | ||
2. [use-redux-agent](https://www.npmjs.com/package/use-redux-agent) react hook ,用来代替 `react-redux`. | ||
|
||
## 文档 | ||
|
||
如果你对`agent-reducer`感兴趣,想要更深入的了解和使用它,请移步至[document](https://github.com/filefoxper/agent-reducer/blob/master/documents/zh/index.md)。 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
module.exports = (api) => { | ||
return api.env('test') ?{ | ||
plugins: [ | ||
["@babel/plugin-transform-runtime"], | ||
['@babel/plugin-proposal-export-namespace-from'], | ||
[ | ||
'@babel/plugin-proposal-class-properties', | ||
{loose: true}, | ||
] | ||
], | ||
presets: [ | ||
[ | ||
'@babel/preset-env', | ||
{ | ||
targets: { | ||
node: 'current' | ||
} | ||
} | ||
] | ||
] | ||
}:{ | ||
plugins: [ | ||
["@babel/plugin-transform-runtime"], | ||
['@babel/plugin-proposal-export-namespace-from'], | ||
[ | ||
'@babel/plugin-proposal-class-properties', | ||
{loose: true}, | ||
] | ||
], | ||
presets: [ | ||
[ | ||
'@babel/preset-env', | ||
{ | ||
modules: false, | ||
targets: { | ||
"browsers": ["last 2 versions", "ie >=9"] | ||
}, | ||
useBuiltIns: "usage", | ||
corejs: {version: 3, proposals: true} | ||
} | ||
] | ||
] | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
# applyMiddleWares(...middleWares) | ||
|
||
It is a function for chaining `MiddleWares` together to be one `MiddleWare`. | ||
|
||
```typescript | ||
function applyMiddleWares( | ||
...middleWares: (MiddleWare | LifecycleMiddleWare)[] | ||
): MiddleWare | LifecycleMiddleWare | ||
``` | ||
* middleWares - `MiddleWares` | ||
|
||
You can check the [example](https://github.com/filefoxper/agent-reducer/blob/master/src/libs/middleWarePresets.ts) in our project. | ||
|
||
Go back to [API Reference](https://github.com/filefoxper/agent-reducer/blob/master/documents/en/api/index.md) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,112 @@ | ||
# createAgentReducer( originAgent, middleWareOrEnv, env ) | ||
|
||
This function is used for changing an `OriginAgent` model to an `AgentReducer` function, and using MiddleWares on it. If you are not familiar with the concept about `OriginAgent` and `AgentReducer`, you can take a look at the [concept](https://github.com/filefoxper/agent-reducer/blob/master/documents/en/introduction/concept.md). | ||
|
||
```typescript | ||
function createAgentReducer< | ||
S, | ||
T extends OriginAgent<S> = OriginAgent<S> | ||
>( | ||
originAgent: T | { new (): T }, | ||
middleWareOrEnv?: (MiddleWare & { lifecycle?: boolean }) | Env, | ||
env?: Env | ||
): AgentReducer<S, Action, T> | ||
``` | ||
|
||
* originAgent - the model class or object. | ||
* middleWareOrEnv - it is an optional param, if you want to use `MiddleWare`, it can be a `MiddleWare`, if you want to set running env without `MiddleWare`, it can be an env config. | ||
* env - if you want to set both `MiddleWare` and running env, you can set an env config here. | ||
|
||
Be careful, `LifecycleMiddleWare` can not work with this api directly, so, if you want to use `LifecycleMiddleWares.takeLatest`, you'd better set it with api [useMiddleWare](https://github.com/filefoxper/agent-reducer/blob/master/documents/en/api/use_middle_ware.md) or [middleWare](https://github.com/filefoxper/agent-reducer/blob/master/documents/en/api/middle_ware.md). | ||
|
||
You can find how to config an env object [here](https://github.com/filefoxper/agent-reducer/blob/master/documents/en/guides/about_env.md) and what is `MiddleWare` [here](https://github.com/filefoxper/agent-reducer/blob/master/documents/en/guides/about_middle_ware.md). If you want to know how to make `AgentReducer` working with another reducer tool, please check it [here](https://github.com/filefoxper/agent-reducer/blob/master/documents/en/guides/with_other_reducer_tools.md). | ||
|
||
You can check example [here](https://github.com/filefoxper/agent-reducer/blob/master/test/en/api/createAgentReducer.spec.ts). | ||
|
||
examples about how to use `createAgentReducer`: | ||
```typescript | ||
import { | ||
createAgentReducer, | ||
middleWare, | ||
MiddleWares, | ||
OriginAgent | ||
} from "agent-reducer"; | ||
|
||
describe('how to use createAgentReducer',()=>{ | ||
|
||
/** | ||
* this is a simple count model (OriginAgent) | ||
*/ | ||
class CountAgent implements OriginAgent<number> { | ||
// it persist a number type state | ||
state = 0; | ||
|
||
constructor(state?:number) { | ||
this.state=state||0; | ||
} | ||
|
||
// you can write a arrow function method | ||
// the method returns a changed state | ||
increase = (): number => this.state + 1; | ||
|
||
// you can write a normal method too | ||
decrease(): number { | ||
return this.state - 1; | ||
} | ||
|
||
walk(increment: boolean): number { | ||
return increment ? this.increase() : this.decrease(); | ||
} | ||
|
||
// the method params is instead of 'action' in reducer, this is freedom in 'agent-reducer' | ||
sum(...counts: number[]): number { | ||
return this.state + counts.reduce((r, c): number => r + c, 0); | ||
}; | ||
|
||
async sumRemoteValue(remoteValue:number){ | ||
return this.sum(remoteValue); | ||
} | ||
|
||
} | ||
|
||
it('a basic usage',()=>{ | ||
// createAgentReducer has a simple reducer processor inside. | ||
const {agent}=createAgentReducer(CountAgent); | ||
agent.increase(); | ||
expect(agent.state).toBe(1); | ||
}); | ||
|
||
it('input params into model by use model construct',()=>{ | ||
// createAgentReducer has a simple reducer processor inside. | ||
// we can pass a model instance in, if we need some params for model. | ||
const {agent}=createAgentReducer(new CountAgent(1)); | ||
agent.increase(); | ||
expect(agent.state).toBe(2); | ||
}); | ||
|
||
it('use MiddleWare directly on createAgentReducer',async ()=>{ | ||
// createAgentReducer has a simple reducer processor inside. | ||
const {agent}=createAgentReducer(CountAgent,MiddleWares.takePromiseResolve()); | ||
await agent.sumRemoteValue(2); | ||
expect(agent.state).toBe(2); | ||
}); | ||
|
||
it('use env directly on createAgentReducer',async ()=>{ | ||
// createAgentReducer has a simple reducer processor inside. | ||
const {agent}=createAgentReducer(CountAgent,{expired:true}); | ||
await agent.increase(); | ||
expect(agent.state).toBe(0); | ||
}); | ||
|
||
it('use both MiddleWare and env directly on createAgentReducer',async ()=>{ | ||
// createAgentReducer has a simple reducer processor inside. | ||
const {agent}=createAgentReducer(CountAgent,MiddleWares.takePromiseResolve(),{strict:false}); | ||
await agent.sumRemoteValue(2); | ||
expect(agent.state).toBe(2); | ||
}); | ||
|
||
}); | ||
``` | ||
All what a `AgentReducer` function can provide have described clear in section [with other reducer tools](https://github.com/filefoxper/agent-reducer/blob/master/documents/en/guides/with_other_reducer_tools.md), please check it in that section. | ||
|
||
Go back to [API Reference](https://github.com/filefoxper/agent-reducer/blob/master/documents/en/api/index.md) |
Oops, something went wrong.