精读《React PowerPlug 源码》 (2)

实现依然很简单,add remove clear 都利用 Value 提供的 set 进行赋值,只要实现几个操作数组方法即可:

const unique = arr => arr.filter((d, i) => arr.indexOf(d) === i); const hasItem = (arr, item) => arr.indexOf(item) !== -1; const removeItem = (arr, item) => hasItem(arr, item) ? arr.filter(d => d !== item) : arr; const addUnique = (arr, item) => (hasItem(arr, item) ? arr : [...arr, item]);

has 方法则直接复用 hasItem。核心还是利用 Value 的 set 函数一招通吃,将操作目标锁定为数组类型罢了。

2.6. map

Map 的实现与 Set 很像,类似 ES6 的 Map。

用法

与 Set 不同,Map 允许设置 Key 名。需要注意的是,initial 是对象,而不是 Map 对象。

<Map initial={{ sounds: true, music: true, graphics: "medium" }}> {({ set, get }) => ( <Tings> <ToggleCheck checked={get("sounds")} onChange={c => set("sounds", c)}> Game Sounds </ToggleCheck> <ToggleCheck checked={get("music")} onChange={c => set("music", c)}> Bg Music </ToggleCheck> <Select label="Graphics" options={["low", "medium", "high"]} selected={get("graphics")} onSelect={value => set("graphics", value)} /> </Tings> )} </Map> 源码

源码地址

原料:Value

依然利用 Value 组件,value 重命名为 values 且初始值为 {},增加了 set get clear has delete 方法,保留 reset 方法。

由于使用对象存储数据结构,操作起来比数组方便太多,已经不需要再解释了。

值得吐槽的是,作者使用了 != 判断 has:

export default { has: key => values[key] != null; }

这种代码并不值得提倡,首先是不应该使用二元运算符,其次比较推荐写成 values[key] !== undefined,毕竟 set('null', null) 也应该算有值。

2.7. state

State 纯粹为了替代 React setState 概念,其本质就是换了名字的 Value 组件。

用法

值得注意的是,setState 支持函数和值作为参数,是 Value 组件本身支持的,State 组件额外适配了 setState 的另一个特性:合并对象。

<State initial={{ loading: false, data: null }}> {({ state, setState }) => { const onStart = data => setState({ loading: true }); const onFinish = data => setState({ data, loading: false }); return ( <DataReceiver data={state.data} onStart={onStart} onFinish={onFinish} /> ); }} </State>

源码地址

原料:Value

依然利用 Value 组件,value 重命名为 state 且初始值为 {},增加了 setState 方法,保留 reset 方法。

setState 实现了合并对象的功能,也就是传入一个对象,并不会覆盖原始值,而是与原始值做 Merge:

export default { setState: (updater, cb) => set( prev => ({ ...prev, ...(typeof updater === "function" ? updater(prev) : updater) }), cb ); } 2.8. Active

这是一个内置鼠标交互监听的容器,监听了 onMouseUp 与 onMouseDown,并依此判断 active 状态。

用法 <Active> {({ active, bind }) => ( <div {...bind}> You are {active ? "clicking" : "not clicking"} this div. </div> )} </Active> 源码

源码地址

原料:Value

依然利用 Value 组件,value 重命名为 active 且初始值为 false,增加了 bind 方法。

bind 方法也巧妙利用了 Value 提供的 set 更新状态:

export default { bind: { onMouseDown: () => set(true), onMouseUp: () => set(false) } }; 2.9. Focus

与 Active 类似,Focus 是当 focus 时才触发状态变化。

用法 <Focus> {({ focused, bind }) => ( <div> <input {...bind} placeholder="Focus me" /> <div>You are {focused ? "focusing" : "not focusing"} the input.</div> </div> )} </Focus> 源码

源码地址

原料:Value

依然利用 Value 组件,value 重命名为 focused 且初始值为 false,增加了 bind 方法。

bind 方法与 Active 如出一辙,仅是监听时机变成了 onFocus 和 onBlur。

2.10. FocusManager

不知道出于什么考虑,FocusManager 的官方文档是空的,而且 Help wanted。。

正如名字描述的,这是一个 Focus 控制器,你可以直接调用 blur 来取消焦点。

用法

笔者给了一个例子,在 5 秒后自动失去焦点:

<FocusFocusManager> {({ focused, blur, bind }) => ( <div> <input {...bind} placeholder="Focus me" onClick={() => { setTimeout(() => { blur(); }, 5000); }} /> <div>You are {focused ? "focusing" : "not focusing"} the input.</div> </div> )} </FocusFocusManager> 源码

源码地址

原料:Value

依然利用 Value 组件,value 重命名为 focused 且初始值为 false,增加了 bind blur 方法。

blur 方法直接调用 document.activeElement.blur() 来触发其 bind 监听的 onBlur 达到更新状态的效果。

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/zywxyy.html