@exodus/atoms
安装
pnpm add @exodus/atoms
什么是原子吗?
原子是一个数据源包,它通过三种不同的方法暴露出单个数据:
- 获取(): 读取数据
- 设置( 新数值):设置原子值,屏蔽直到所有观察者解决.
- 观察( 同步( 数据) ) qq ):观察数据变化。 最初将使用当前数据值。 观察员正在等待一系列安排.
- 重设( c):清除存储值。 下一个
get()调用将返回默认值*,并用默认值调用观察者.
数据来源
这个库为从我们应用中所使用的多个数据源创建原子提供了帮助.
| 起来 | 设定 | 观察 | |
|---|---|---|---|
| 内存 | ✅ | ✅ | ✅ |
| 存储 | ✅ | ✅ | ✅ |
| 键盘 | ✅ | 🟡 * | ✅ |
| 事件发射器 | ✅ | ❌ | ✅ |
*一个键盘原子需要一个特殊的 isSoleWriter 允许写入的参数.
另见:
注:这所图书馆最初曾主办一大批媒体特有工厂,后被搬出,如上两所. 以上可能也随之而来,而这个库只执行常见的媒体不可知原子行为.
解决问题
从理论上讲,所有原子都应该有类似的行为. 在实践中,目前有一些不一致的行为,我们的目标是在未来加以纠正,特别是围绕一个事件发射器产生的记忆原子和原子:
- 内存原子挂起
get()若无defaultValue提供. - 内存和事件 Emitter 原子观测器是非屏蔽的,即:.
memoryAtom.set()火和遗忘
使用量
import { EventEmitter } from 'events'
import {
createInMemoryAtom,
createStorageAtomFactory,
fromEventEmitter,
createKeystoreAtom,
} from '@exodus/atoms'
// In memory atoms
const availableAssetNamesAtom = createInMemoryAtom({
defaultValue: {},
})
// Storage atoms
const storageAtomFactory = createStorageAtomFactory({ storage })
const acceptedTermsAtom = storageAtomFactory({
key: 'acceptedTerms',
defaultValue: false,
isSoleWriter: true,
})
// Event emitter
const geolocation = new EventEmitter()
const geolocationAtom = fromEventEmitter({
emitter: geolocation,
event: 'geolocation',
get: async () =>
new Promise((resolve, reject) => navigator.geolocation.getCurrentPosition(resolve, reject)),
})
navigator.geolocation.watchPosition((position) => {
geolocation.emit('geolocation', position)
})
// keystore
const keystoreAtom = createKeystoreAtom({
keystore, // see @exodus/keystore-mobile
config: {
key: 'my-secret',
defaultValue, // optional
isSoleWriter, // if you plan to call set() on this atom instance
},
})
增强器
为了计算衍生值,将多个原子结合到其他有用的衍生物中,并进行其他有用的衍生,可以使用一串增强子. 下面是一份并非详尽无遗的清单,请检查一下 ./弧/增强 为了更多.
计算( {原子, 选择器} ): 只读原子
通过对观测到的数据源应用一个选择器函数,从另一个原子中计算一个原子.
示例
import { createInMemoryAtom, compute } from '@exodus/atoms'
const yearAtom = createInMemoryAtom({ defaultValue: 2025 })
const isDoorsOfStoneOutYetAtom = compute({
atom: yearAtom,
selector: (year) => year > 2040,
})
isDoorsOfStoneOutYetAtom.observe(console.log) // false
组合({ [键]:原子}):只读原子
将多个原子组合为一个原子 :
combinedAtom.observe:在所有原子释放出值时,首次起火.combinedAtom.get: 解决输入中包含所有原子值的对象.
示例
import { createInMemoryAtom, combine } from '@exodus/atoms'
const nameAtom = createInMemoryAtom()
const ageAtom = createInMemoryAtom()
const userAtom = combine({
name: nameAtom,
age: ageAtom,
})
userAtom.observe(console.log) // hangs until both name and age are set
nameAtom.set('Voldemort')
ageAtom.set(25)
// userAtom atom fires with { name: 'Voldemort', age: 25 }
dedupe( 原子)
默认情况下,原子进行浅等检查,以确定新写值与当前值是否不同,并避免通知不通知观察者. 如果你想要深刻的平等检查,使用 dedupe.(更妙的是,首先不要给原子写出非常等同的物体,而且不要使用 dedupe) (中文(简体) )
示例
import { createInMemoryAtom, dedupe } from '@exodus/atoms'
const userAtom = createInMemoryAtom({ defaultValue: { name: 'Voldemort', age: 25 } })
const dedupedUserAtom = dedupe(userAtom)
userAtom.set({ name: 'Voldemort', age: 25 }) // `userAtom` observers are notified
dedupedUserAtom.set({ name: 'Voldemort', age: 25 }) // `dedupedUserAtom` observers are NOT notified
与序列化({原子、序列化、去序列化})
如果你将数据存储在一个需要(去)序列化的原子中,例如存储原子,而数据通过JSON.stringify / JSON在回转中无法存活. 剖析, 使用 withSerialization 提供自定义序列化.
示例
import BJSON from 'buffer-json'
import { createInMemoryAtom, withSerialization } from '@exodus/atoms'
const rawPublicKeysAtom = createInMemoryAtom()
const publicKeysAtom = withSerialization({
atom: rawPublicKeysAtom,
serialize: BJSON.stringify,
deserialize: BJSON.parse,
})
publicKeysAtom.set({
bitcoin: Buffer.from([...]),
ethereum: Buffer.from([...]),
})
相差( 原子)
如果您想要同时获得原子释放的当前值和先前值,请使用 difference。 。 。 .
示例
import { createInMemoryAtom, difference } from '@exodus/atoms'
const nameAtom = createInMemoryAtom({ defaultValue: 'Tom' })
const nameChangeAtom = difference(nameAtom)
nameChangeAtom.observe(console.log)
nameAtom.set('Voldemort')
// nameChangeAtom emits
// { previous: 'Tom', current: 'Voldemort' }
过滤器( 原子, 上游)
如果你只对一个子集的数值感兴趣 一个原子的分集,使用 filter数字 :
示例
import { createInMemoryAtom, filter } from '@exodus/atoms'
const nameAtom = createInMemoryAtom({ defaultValue: 'Tom' })
const unusualNameAtom = filter(nameAtom, (name) => !['Tom', 'Dick', 'Harry'].includes(name))
unusualNameAtom.observe(console.log)
nameAtom.set('Dick') // unusualNameAtom doesn't emit
nameAtom.set('Harry') // unusualNameAtom doesn't emit
nameAtom.set('Voldemort') // unusualNameAtom emits 'Voldemort'