dingDang ( 一个治理react数据层的产物 )
github地点
我们将dingDang定义为一个产物而不是一个框架亦或工具包 。
由于dingDang在设想之初就将用户的开辟体验放在第一位,而机能题目则放在第二位。
固然这并不意味着我们就是一个机能很蹩脚的产物,只是说我们会在机能能够接收的范围内尽量的去让开辟者的开辟体验更好。
事实上dingDang的内部数据全部都采纳了immutable数据范例。
dingDang中运用了大批的 Promise 于 immutableJS , 假如你对此不太熟习,能够先熟习一下 这两个知识点。
熟悉 DingDang
DingDang装潢器 , 统统故事的最先 , 现在 仅仅只需 sceneStorage 一个参数 。
重要用来定义场景的暂时数据存储计划。
比方说:
在react-web 中 你应当采纳sessionStorage 或许 localStorage ,
而在react-native 中,你应当采纳AsyncStorage 。
在sceneStorage中的3个函数 一切的返回值 要求是规范的 JS Object , set 要领的 key 我们也会传输一个规范的 JS Object
@DingDang({
sceneStorage: {
set: (k, v) => sessionStorage.setItem(k, JSON.stringify(v)),
get: (k) => JSON.parse(sessionStorage.getItem(k)),
del: (k) => sessionStorage.removeItem(k)
}
})
class App extends React.Component {
render() {
return (
<HashRouter>
<Layout>
</Layout>
</HashRouter>
)
}
}
render(
<App />,
document.querySelector("#app")
)
熟悉一个完全的Store
const store = {
namespace: 'demoStore',
state: {},
rules: {},
reducer: {},
effect: {},
initialization: () => false,
destroy: () => false
}
事实上,store中只需namespace字段是必需的,其他的字段假如你不须要的话,能够不写。
namespace(定名空间)
该属性的值是一个字符串 , 在dingDang中请务必保证namespace的唯一性,由于我们须要以此为根据去剖断用户是不是进入了一个全新的场景。
state (状态机)
该属性中重要用来存储store中的一切数据集 , 一般来讲dingDang会将这里的数据都转换为immutable范例。
rules (划定规矩)
起首让我们来看一个完全的rules的案例:
export default {
namespace: 'demoStore',
state: {
name: '张三'
},
rules: {
name: [
{
validate: (state, name) => name ? true : false,
error: '用户姓名不能为空',
miss:false
},
{
validate: (state, name) => name.length < 6,
error: '用户姓名最大长度不能超过6!',
miss:true
}
]
}
}
rules 中设置的实际上是针对state 中数据的校验机制 ,比方在我们的state 中有name这个字段 ,
那末你能够在 rules中也设置一个 对应的name字段 , 但是在rules中 , 该字段的值必需为数组,
详细的校验划定规矩,我们会根据数据的先后顺序来实行。
数据中存储的是每个 自力的 rule ,一个规范的 rule以下:
{
validate: (state, name) => name ? true : false,
error: '用户姓名不能为空',
miss:false
}
validate : 值为一个推断函数 , 该函数我们会自动的注入全量的state参数, 以及你行将给予字段的新值 ,
比方:name 。 这里的校验逻辑为: 假如满足你所需的花样 ,那末返回true , 不然false
error: 缺点提醒 , 在实行validate获得false以后抛出的非常信息
miss : 定义是不是丧失, 这里的寄义是指, 假如行将给予的新值不能满足校验前提, 那末新的值是不是丧失掉(即不存储进state)
如不定义该字段, 那末该字段默以为false , 即不丧失 ,依旧给予state。
reducer (摺叠器)
该字段内存储的应当都是纯函数 ,在这里你能够直接去针对state给予全新的值 , 起首让我们来看一段相对完全的reducer代码案例:
export default {
namespace: 'orderStore',
state: {
goodsList: [
{
id: 1,
name: '方便面',
price: 2
},
{
id: 2,
name: '笔记本电脑',
price: 3281
}
],
cart: []
}
reducer: {
addToCart: (state, goods) => {
return state.set('cart', state.get('cart').push(goods));
}
}
}
正如上面的demo所示 , 我们会为reducer 中的每个函数的 第一个参数都注入一个全量的 immutable 范例的state ,
而第二个参数则是你在挪用的时刻传入的。我们对reducer的要求是,末了你必需返回一个你希冀的、全新的、全量的state。
下面我们看一段挪用reducer 的案例代码:
@Page(Store)
export default class GoodsList extends React.Component {
static injectProps = {
goodsList: [],
cart: []
}
_addToCart = async (n) => {
const {execReducer} = this.props;
try {
await execReducer('addToCart')(n)
} catch (err) {
console.log(err)
}
}
render() {
const {injectProps: {goodsList}} = this.props;
return (
<Layout>
<Row>
<Col>
<Table rowKey={'id'} dataSource={goodsList}>
<Column title="商品名称" dataIndex="name"/>
<Column title="商品价格" dataIndex="price"/>
<Column title="操纵" render={
(n) => <a href="javascript:void(0);" onClick={
() => this._addToCart(n)
}>到场购物车</a>
}/>
</Table>
</Col>
</Row>
<Row>
<Col>
<Link to="/balance"><Button>去结算</Button></Link>
</Col>
</Row>
</Layout>
)
}
}
上述的demo中 , 我们愿望你不要被过量的去关注能够关于你来讲未知的代码影响,你只须要关注我们愿望论述的内容即可(即_addToCart函数),
起首我们应当明白_addToCart函数是一段挪用reducer的代码 , 其次我们观察到 , _addToCart函数采纳了async await 的体式格局来誊写,
申明该函数是异步的 , 而且返回了一个Promise对象给我们 。
事实上,在你实行reducer时,dingDang内部有能够会去rules中取到对应的划定规矩举行校验,假如出现非常的话会reject出来给你 , 所以这里
catch到的err实际上是你的rules中所设置的信息 , 同时假如你的reducer没有任何缺点, dingDang依旧会有返回值给你,这个返回值是reducer
以后的一个全新的state。
effect (副作用的)
我们将这里定义为副作用的 , 也就是愿望你将一切的非纯函数在这里定义(依赖于外部要素的函数,雷同输入并不是能保证获得雷同的效果 ,比方挪用API)。
通例,让我们看一段完全的effect案例:
export default {
namespace: 'orderStore',
state: {
goodsList: [],
cart: []
}
reducer: {
addToCart: (state, goods) => {
return state.set('cart', state.get('cart').push(goods));
}
},
effect:{
queryGoodsList: async ({resolve , reject , state , execReducer , onChangeState} , params) => {
const result = await queryGoodsListByAPI(params);
if( result.success ){
await onChangeState(result.goodsList).catch(err => reject(err));
resolve(true)
}else {
reject( result.error )
}
}
}
}
effect 的参数,我们注入的比较多, resolve 、 reject 这里就不作诠释了 , 假如你不是很清晰, 发起去复习一下Promise 。state 也不作过量的诠释了。
这里我们轻微来提一下 execReducer 和 onChangeState 这两个函数 。 execReducer 在前面我们也见过 , 这个函数属于dingDang的体系级函数,重要用来
辅佐你去挪用reducer。 onChangeState 也是一个dingDang体系级函数 , 这个函数是便于你直接去修正state中的数据 。
我们注重辨别一下reducer 和 onChangeState 的区分 , 一般来讲reducer的挪用体式格局以下:
execReducer('addToCart')(params);
而onChangeState的挪用体式格局
onChangeState(jsObjectParams)
我们总结归纳综合一下,reducer实际上是你用往来来往挪用你本身声明的指定的一个reducer函数 , 而onChangeState 实际上是直接去修正的state中的值 。 一般来讲,
假如你无需做营业逻辑, 仅仅只是想把一个数据放进state , 我们引荐你运用 onChangeState 的体式格局, 请不要忧郁rules 的校验题目 onChangeState 依旧
会去实行rules的校验代码 , 而假如您不仅仅是将一个数据放进state , 在这中心能够另有许多营业逻辑代码, 那末我们引荐你本身去写一个reducer , 然后运用
execReducer 来举行挪用
initialization (store生命周期中的初始化)
initialization 是一个初始化函数 , 这里不想过量的说什么 , 重要重点说一下 , 我们为这个函数注入了
execReducer 、 execEffect 、 onChangeState
destroy (store生命周期中的烧毁)
与initialization同理 , 注入的参数也雷同
体系级函数引见
execReducer
高阶函数 , 重要用来挪用 reducer , 返回Promise
execEffect
高阶函数 , 重要用来挪用 effect , 返回Promise
onChangeState
简化修正state中值的体式格局
Page 装潢器
用来装潢一个页面的进口 ,装潢以后的页面 能够运用声明式注入 demo案例以下
@Page(store)
class Home extends React.Component {
static injectProps = {
initName: null,
name: null
}
render() {
const {injectProps: {initName, name}, onChangeState} = this.props;
return (
<div>
<h1> {initName} </h1>
<h1> {name} </h1>
<button onClick={() => onChangeState({initName: '首屏笔墨被变化以后'})}>变首屏笔墨</button>
<Card/>
</div>
)
}
}
Component装潢器
用来装潢一个页面下的子组件,装潢以后的页面 能够运用声明式注入 demo案例以下
@Component
class Card extends React.Component {
constructor(props) {
super(props)
this.state = {
error: ''
}
}
static injectProps = {
name: null
}
render() {
const {injectProps: {name}} = this.props;
return (
<div>
{name}<span style={{marginLeft: 20, color: 'red'}}>{this.state.error}</span>
<button onClick={this._onChangeName}>变更</button>
</div>
)
}
_onChangeName = () => {
const {onChangeState} = this.props;
onChangeState({name: '李四李四李四李四李四李四'}).catch(e => this.setState({error: e}))
}
}
injectProps (声明式注入)
在组件中运用 static injectProps 的体式格局能够来声明 让dingDang 从store中为你注入哪些数据。
ScenePage (场景页面)
在某些营业背景下,我们能够须要多个页面来完全一组营业。
假定我们须要 A B C 3个页面来完成一组营业 , 在这组营业中 数据实在基本上是雷同的, 针对数据的某些营业操纵也是雷同的。
在这类背景下,我们提出了场景的观点。
我们对场景的定义:多个页面之间针对统一组营业数据举行的一连串行动行动来完成的一组营业,我们称之为场景。
一般的Page装潢器装潢以后的页面只能取本身自力的那份store , 而运用ScenePage装潢以后的多个页面 , 只需绑定的Store
的namespace雷同,那末这个Store的声明周期将一向存在,直到用户跳出当前场景。
运用
npm install 0.1.1-alpha --save