我们很高兴地宣布 Recoil 0.4 的发布,它具有可配置的选择器缓存、针对多个原子进行事务操作的改进 API,以及其他优化和修复。
可配置的选择器缓存
新的 cachePolicy_UNSTABLE
属性在 选择器 和 选择器族 中允许您配置选择器内部缓存的缓存行为。此属性对于减少在具有大量选择器或选择器具有大量变化依赖项的应用程序中的内存很有用。
以下是如何使用此新属性的示例
const clockState = selector({
key: 'clockState',
get: ({get}) => {
const hour = get(hourState);
const minute = get(minuteState);
const second = get(secondState); // will re-run every second
return `${hour}:${minute}:${second}`;
},
cachePolicy_UNSTABLE: {
// Only store the most recent set of dependencies and their values
eviction: 'most-recent',
},
});
在上面的示例中,clockState
每秒重新计算一次,将一组新的依赖项值添加到内部缓存中,这可能会随着时间的推移导致内存问题,因为内部缓存会无限期地增长。使用 most-recent
驱逐策略,内部选择器缓存将只保留最近的一组依赖项及其值,以及基于这些依赖项的实际选择器值,从而解决内存问题。
当前的驱逐选项是
lru
- 当大小超过maxSize
时,从缓存中驱逐最不常用的值。most-recent
- 只保留最新的值。keep-all
(默认) - 保留缓存中的所有条目,不驱逐。
注意:默认的驱逐策略 (当前为
keep-all
) 可能会在将来发生变化。
包含多个原子的事务
引入了一个用于将多个原子一起更新为单个事务的改进 API。新的 useRecoilTransaction_UNSTABLE()
hook 比以前更容易、更高效、更安全。这个新的 hook 应该最终取代大多数 useRecoilCallback()
的用法,但是此版本只是一个初始实现,存在一些 限制,这些限制将在未来的版本中得到解决。
示例
假设我们有两个原子,positionState
和 headingState
,并且我们希望将它们一起更新为单个操作的一部分,其中 positionState
的新值是 当前 positionState
和 headingState
值的函数。您可以通过事务来完成此操作,该事务必须是一个没有副作用的纯函数
const goForward = useRecoilTransaction_UNSTABLE(({get, set}) => (distance) => {
const heading = get(headingState);
const position = get(positionState);
set(positionAtom, {
x: position.x + cos(heading) * distance,
y: position.y + sin(heading) * distance,
});
});
然后,您只需在事件处理程序中调用 goForward(distance)
即可执行事务。这将根据 当前 值更新状态,而不是组件渲染时的状态。您还可以在事务期间读取先前写入的值。由于在更新器执行期间不会提交其他更新,因此您将看到一致的状态存储。
使用 useRecoilCallback()
的先前方法可能如下所示
const goForward = useRecoilCallback(({snapshot, gotoSnapshot}) => (distance) => {
const mutatedSnapshot = snapshot.map(({get, set}) => {
const heading = get(headingState);
const position = get(positionState);
set(positionState, {
x: position.x + cos(heading) * distance,
y: position.y + sin(heading) * distance,
});
});
gotoSnapshot(mutatedSnapshot);
});
这有以下缺点
- 管理快照的完整通用性会产生性能开销。
- 错误的机会更多:快照可能会被保留并在将来使用。由于快照包含完整的 Recoil 状态,而不仅仅是变更集,因此可能会意外地回退创建和提交快照之间发生的更改。
Reducer 示例
您还可以使用此 hook 来创建在多个原子上执行操作的 reducer 模式
const reducer = useRecoilTransaction_UNSTABLE(({get, set}) => action => {
switch(action.type) {
case 'goForward':
const heading = get(headingState);
set(positionState, position => {
x: position.x + cos(heading) * action.distance,
y: position.y + sin(heading) * action.distance,
});
break;
case 'turn':
set(headingState, action.heading);
break;
}
});