用一行代码进行状态管理
如果您像我一样,觉得必须有一种更简单的状态管理方法,那么您会喜欢ActiveJS为您做的事情。
我感觉自己像是在推销蛇油,但在过去的 10 个月里,我一直在尝试让状态管理尽可能直观和简单,因为我无法忍受目前的状态管理。
为了实现高效的状态管理,我们需要做以下几件事
- 类型安全的数据结构
- 可以在突变时发出事件的数据结构
- 可以保证不变性的数据结构
- 可以通过会话持久化的数据结构
标题承诺用一行代码实现所有这些,所以就在这里。
const dataUnit = new DictUnit({
id: 'data', immutable: true, persistent: true, cacheSize: Infinity,
initialValue: {a: 1}
})
// every option is optional, including the initialValue
// DictUnit has empty object {} as it's default value
(好吧,有 4 行,但我已将其格式化,因此您不必滚动:)
JavaScript 没有这样的东西,这就是 ActiveJS 出现的原因,并且随之出现了称为Units的反应式数据结构,其中之一就是DictUnit,它始终存储并确保字典对象的值。
您可能已经从我们传递给 DictUnit 的配置选项中有所了解,并猜到了它的全部内容,但详细说明 DictUnit 是:
- 可观察的
- 反应式
- 类型安全
- 不可变
- 坚持不懈,并且
- 已启用缓存
让我们用我们都理解的语言看看这是什么意思,代码如下:
可观察的
DictUnit扩展了 RxJS Observable 类,因此您可以订阅它并在其上应用所有 RxJS 操作符,就像在 Observable 上一样。
// subscribe for the value
dataUnit.subscribe(value => console.log(value))
// logs {a: 1} immediately and will log future values
dataUnit instanceof Observable; // true
反应式
当您更新 DictUnit 的值时,它会将其发送给所有观察者,以便他们能够访问最新值。
// non-functional dispatch
dataUnit.dispatch({b: 2, c: 3})
// observers get {b: 2, c: 3}
// now dataUnit's value is {b: 2, c: 3}
// functional-dispatch
dataUnit.dispatch(value => {return {...value, d: 4}})
// observers get {b: 2, c: 3, d: 4}
// we don't have to dispatch new values manually,
// DictUnit provides a better way to update properties
// update a single property
dataUnit.set('d', 5)
// observers get {b: 2, c: 3, d: 5}
// delete properties
dataUnit.delete('b', 'd') // 'b' and 'd' got yeeted
// observers get {c: 3}
// update multiple properties
dataUnit.assign({a: 1, b: 2})
// observers get {a: 1, b: 2, c: 3}
类型安全
DictUnit 确保值始终是一个字典对象,它将忽略任何无效的值分派。
dataUnit.dispatch(['let', 'me', 'in']); // won't work
dataUnit.dispatch('let me in'); // won't work
dataUnit.dispatch(420); // won't work
dataUnit.dispatch(null); // won't work
dataUnit.dispatch(new Date()); // won't work
dataUnit.dispatch(() => new Date()); // won't work
与 ActiveJS 中的 DictUnit 类似,还有 5 个其他 Unit,用于存储的ListUnitarray
、用于存储的NumUnitnumber
、用于存储的StringUnitstring
、用于存储的BoolUnitboolean
和用于存储任何内容的GenericUnit 。
不可变
immutable 标志确保 DictUnit 不会让值以任何方式发生变异。无论如何,我们还是尝试改变它吧。
const newValue = {c: 3};
dataUnit.dispatch(newValue) // works, value is {c: 3} now
// try mutating the newValue
newValue.c = 'hehe' // works, but
dataUnit.value() // still {c: 3}
// let's try a different approach
const currentValue = dataUnit.value() // {c: 3}
currentValue.c = 'gotcha' // works, but
dataUnit.value() // still {c: 3}
执着的
持久标志使 DictUnit 持久化,这样每当它的值更新时,它都会将该值保存到 LocalStorage,因此如果我们使用相同的标志重新初始化 DictUnit id
,persistent: true
DictUnit 将从 LocalStorage 恢复其值。
dataUnit.dispatch({c: 4}) // saved in LocalStorage
// after refreshing the browser-tab or reinitializing the DictUnit
dataUnit.value() // {c: 4}
// it restored the value from LocalStorage
已启用缓存
如果我告诉你,我们可以回到之前示例中更新的所有值,然后再回到当前值,那会怎么样呢?没错,时间旅行是可以实现的。你只需要指定希望使用该cacheSize
选项返回多少步,默认情况下,它保留 2 个值,最多支持无限个。
// let's reinitialize the Unit to demonstrate cache-navigation
const dataUnit = new DictUnit({
cacheSize: Infinity, initialValue: {a: 1}
})
// now let's dispatch a bunch of values to fill the cache
dataUnit.dispatch({b: 2})
dataUnit.dispatch({c: 3})
dataUnit.dispatch({d: 4})
dataUnit.dispatch({e: 5})
// now the value is {e: 5}, and
// the cache looks like this [{a: 1}, {b: 2}, {c: 3}, {d: 4}, {e: 5}]
// go back 1 step
dataUnit.goBack()
// now value is {d: 4}
// go back 2 steps
dataUnit.jump(-2) // negative means back, positive means forward
// now value is {b: 2}
// jump to the last value in cache
dataUnit.jumpToEnd()
// now value is {e: 5}
// jump to the first value in cache
dataUnit.jumpToStart()
// now value is {a: 1}
// go forward 1 step
dataUnit.goForward()
// now value is {b: 2}
就这样,朋友们,一切都完成了。
我们还有一些 DictUnit 的功能没有讲到,比如管理异步 API 调用之类的。不过这些也许可以留到下一篇文章再讲。
与此同时,注意安全,尽量享受乐趣,并前往ActiveJS 网站或文档,了解有关如何帮助您以最少的努力管理状态的更多信息。
如果您想亲自尝试一下,这里是StackBlitz 游乐场链接。
这是可视化游乐场的链接,您无需编写任何代码即可尝试。
另外,我忘了告诉你,这是我在任何平台上发表的第一篇文章,请告诉我我做得是否还好,或者是否有可以改进的地方。
干杯
🌏 ActiveJS 网站
📖 ActiveJS 文档
🤾♂️ ActiveJS 游乐场
💻 ActiveJS GitHub Repo(也许放个 ⭐ :)