acc节点:React Native Reanimated v1 声明式动画中的累积求和原语
【免费下载链接】react-native-reanimatedReact Native's Animated library reimplemented项目地址: https://gitcode.com/GitHub_Trending/re/react-native-reanimated
acc(node)是 React Native Reanimated v1 节点体系中的一个基础原语,它记录并返回给定节点的历史求值总和,用于把离散的动画信号累积成持续变化的数值。本文以版本化文档 nodes/acc.md 为核心,结合 v1 声明式 API 的节点模型(clock.md、declarative.md 等)与"单帧至多求值一次"的架构算法,讲清acc的语义、适用场景、组合用法与注意事项,帮助你写出可在 UI 线程运行的"积分器"式动画逻辑。
一、acc的语义:把每次求值累加起来
acc节点的定义非常简洁,接口签名如下(完整原文见 acc.md):
acc(node);其行为可以概括为:
返回给定节点的累积值(accumulated value)。该节点内部维护一个"和"(sum),记录给定节点所有历史求值的总和;每次它被求值时,都会把当前时刻
node的值累加到该总和上,并返回累加后的结果。
用伪代码可以更直观地表达这一语义:
// acc 节点内部(概念示意) accState.sum = 0; function evaluateAcc(node) { accState.sum = accState.sum + evaluate(node); // 当前求值 + 历史总和 return accState.sum; }换句话说,acc是一个离散时间下的"累加器":它不关心节点当前的瞬时值,而关心节点自挂载以来所有求值结果的累积量。这与同样记录历史差值的diff节点(返回上一次求值与当前求值之差)互为镜像——diff做差分,acc做积分。
acc的输入node可以是任意动画节点(如Value、add、multiply、cond的返回值等),这也体现了 v1 节点体系"节点可任意组合"的设计:见 declarative.md 中"不再操作动画对象,而是操作执行单步动画的节点"这一核心思想。
二、为什么acc是确定性的:v1 的"单帧至多求值一次"算法
要真正理解acc的累积语义,必须了解 v1 架构的一条关键规则。在 about.md 的 "At most once evaluation (the algorithm)" 一节中明确指出:
与原始
Animated库中每个节点在一帧内可能被求值多次不同,Reanimated v1 限制每个节点在一帧内至多被求值一次。当节点被求值后,其值会被缓存;若同一帧内其他节点需要该节点的输出,则直接返回缓存值而不重新求值。
这条规则对acc至关重要:
- 累积口径唯一:由于一帧内
acc至多累加一次,累积结果不会因同一帧内多次引用acc而重复叠加。 - 结果可预测:
acc的返回值只取决于"从挂载到现在一共被求值了多少帧"以及"每帧输入节点的值",与求值顺序、引用次数无关,便于在声明式表达式中反复使用。
该算法的完整求值流程(来自 about.md)为:先分析本帧事件流 → 更新"运行中"的 clock 节点 → 从被更新的节点出发遍历节点树 → 找到连接到视图属性的最终节点并递归求值 → 若仍有运行中的时钟则排队下一帧。acc正是这一遍历过程中被"按帧累积"的普通节点之一。
三、与diff的组合:从"差值"到"累积"的完整信号处理
acc常与diff配合使用。diff的语义是:
diff(node);返回节点"上一次求值的值"与"当前求值"的差;首次求值时直接返回节点当前值。可见diff与acc是时间维度上的一对逆操作:
diff:提取增量(一阶差分),适合检测变化、求变化率;acc:累积增量(求和/积分),适合把增量还原为总量。
一个典型的物理模拟思路是:用diff求出位置节点的位移增量,再通过acc累加出总路程;或者反过来,把acc(速度增量)当作位移。二者都依赖 about.md 中描述的"缓存值 + 至多一次求值"机制来保证"上一次求值"与"本次求值"之间有确定的一帧间隔。
四、实战用法:在声明式节点图中做"积分"
acc的典型价值在于:用纯声明式的节点组合实现本需要用命令式代码维护的累加状态。在 v1 中,节点可挂在Animated.View的样式属性上,也可放在Animated.Code/useCode中随输入节点变化而执行。
4.1 挂在样式上:累积手势或传感器信号
import Animated from 'react-native-reanimated'; const { Value, acc, multiply, cond, eq, set } = Animated; // 每一帧把 gestureDelta(例如手势位移的增量信号)累加进 total const gestureDelta = new Value(0); const total = acc(gestureDelta); // 直接映射到视图变换 // <Animated.View style={{ transform: [{ translateX: total }] }} />这里total每帧返回gestureDelta的历史累积值,等价于一个运行在 UI 线程的"积分器",无需在 JS 侧手动setValue维护和。
4.2 与set+cond配合:可控清零的累加器
acc的累积是持续性的。若需要"重置累积",可用set与cond在节点图中实现条件清零——set会把源节点的值赋给Animated.Value,cond提供条件分支求值(两者详细语义见 set.md 与 cond.md)。
const { Value, acc, cond, eq, set, block } = Animated; const input = new Value(1); // 每帧输入信号 const resetFlag = new Value(0); // 置 1 时清零 const total = acc(input); // 在 useCode 或 Animated.Code 中:清零时把 total 对应的 Value 复位 // set(totalSource, cond(eq(resetFlag, 1), 0, total))结合 block(按顺序求值数组中的节点并返回最后一个节点的值),可以构造"先判断是否需要清零、再输出累积结果"的复合节点块。
4.3 在Animated.Code/useCode中驱动副作用
acc不一定非要绑定到视图属性。v1 提供的Animated.Code组件与useCode钩子允许"当输入节点更新时执行一段节点逻辑":
import Animated from 'react-native-reanimated'; Animated.useCode( () => set(someValue, acc(perFrameDelta)), [perFrameDelta] );useCode的第一个参数是返回节点(或节点数组,数组会被放进block)的工厂函数,第二个参数是依赖数组,依赖变化时节点会重新创建,这正好适合需要随输入信号重建/重置累加器的场景。注意useCode仅在支持 Hooks 的 React Native(≥0.59)上生效。
五、使用acc的注意事项
- 累积是无界的:
acc从节点挂载起一直累加,数值会单调增长(或按输入符号波动),不会自动归零。若用于translateX等样式属性,需自行设计清零逻辑,避免数值溢出或视图飞出屏幕。 - 一帧至多一次求值的隐含约束:
acc的确定性依赖 v1 的"节点缓存 + 至多一次求值"算法(见 about.md)。同一帧内多次引用acc返回的是同一次累加结果,而不是重复叠加,使用时不必担心"被引用多次会累加多次"。 - 首次求值语义:与
diff类似,acc在首次求值时会以当前输入节点的值作为起点(即总和从首个输入值开始),因此挂载时刻的输入值也会计入累积,设计初始条件时需留意。 - 它属于 v1 声明式节点 API:
acc是 v1 节点体系(nodes/目录下 50 余个节点之一)的组成部分,其定位是与add、diff、set、cond、block等基础节点组合出复杂的动画逻辑;当前仓库的源码与 v3/v4 现代 API 已采用 Hook 化的useSharedValue等新模型(见 packages/react-native-reanimated/src 目录),acc作为历史版本 API 记录在 versioned_docs/version-1.x 中。
六、延伸阅读
- 节点体系总览:nodes/add.md、nodes/diff.md、nodes/block.md、nodes/set.md、nodes/cond.md
- 值容器与时钟:value.md、clock.md
- 声明式动画与副作用节点:declarative.md、code.md
- 架构背景:"单帧至多求值一次"算法与设计动机见 about.md
【免费下载链接】react-native-reanimatedReact Native's Animated library reimplemented项目地址: https://gitcode.com/GitHub_Trending/re/react-native-reanimated
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考