实现依然很简单,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. mapMap 的实现与 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. stateState 纯粹为了替代 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 达到更新状态的效果。