
useDerivedValue 完全指南用 react-native-reanimated 构建响应式派生共享值【免费下载链接】react-native-reanimatedReact Natives Animated library reimplemented项目地址: https://gitcode.com/GitHub_Trending/re/react-native-reanimated本指南围绕 react-native-reanimated 的核心 HookuseDerivedValue展开讲解如何在现有共享值Shared Value的基础上派生出新的、始终保持同步的只读共享值并深入其底层 mapper 机制与 Web / Native 双平台实现差异。读完本文你将掌握useDerivedValue的参数契约、依赖数组dependencies的三种用法以及它和useSharedValue、useAnimatedStyle的协作模式能够直接写出可运行的响应式派生动画逻辑。什么是 useDerivedValueuseDerivedValue是 react-native-reanimated 提供的一个 Hook用于创建一个会随一个或多个其他共享值变化而自动更新的共享值引用。它与useSharedValue返回的是同类型的共享值引用实例区别在于useSharedValue的值由你手动赋值而useDerivedValue的值由一个 worklet更新函数根据其他共享值实时计算得出从而实现派生语义。在版本 2.x 中该 API 的完整文档位于 useDerivedValue.md仓库当前主版本未版本化文档位于 useDerivedValue.mdx核心行为保持一致。该 Hook 在包入口中与useSharedValue、useAnimatedStyle等一同导出见 hook/index.ts。函数签名与参数useDerivedValue接受两个参数返回一个派生共享值引用useDerivedValueValue( updater: () Value, // updaterWorklet必填 dependencies?: DependencyList // 依赖数组可选 ): DerivedValueValue参数一updaterWorkletworklet第一个参数是一个 worklet它会在该 worklet 中使用的至少一个共享值发生变化时被触发执行。该 worklet 需要返回一个新的 JS 值number、string、bool、Object、Array 均可返回值会被赋给 Hook 返回的共享值引用。两个值得注意的行为立即执行一次updaterWorklet会在 Hook 首次使用时立刻执行一次用于为返回的共享值计算初始载荷initial payload保证首帧就有正确值。闭包敏感worklet 体内引用的外部变量来自组件作用域的闭包变量会被纳入依赖追踪。从源码可以看到 Hook 的实现入口Native 平台版本 useDerivedValue.native.ts 通过updater.__closure提取 worklet 的闭包变量作为 mapper 的输入inputsWeb 平台版本 useDerivedValue.ts 在闭包为空时会回退使用dependencies数组作为输入这样即使没有 Babel/SWC 插件Web 端也能正常工作。参数二dependenciesArray可选可选的依赖数组。当其中任一值变化导致包裹组件重渲染rerender时Hook 会收到更新。这在你于 worklet 中使用了依赖组件 state 的值时尤为重要。官方文档给出的示意如下const App () { const [state, setState] useState(0); const sv useSharedValue(state); const derived useDerivedValue(() { return sv.value * state; }, dependencies); //... return /; };dependencies的取值有三种情形取值行为undefined省略参数worklet 会在其函数体或闭包来自外部作用域且在 worklet 中使用的变量发生任何变化时被重建空数组[]worklet 只在其函数体变化时被重建值数组[val1, val2, ..., valN]worklet 会在其函数体或给定数组中任一值发生变化时被重建平台差异注意从 useDerivedValue.native.ts 可以看到在 Native 平台上若显式传入dependencies开发模式下会打印警告dependencies should only be used in web implementation.——这是因为 Native 端依赖 worklet 的 Babel 插件自动提取闭包手动传依赖是多余的而在无插件的 Web 端依赖数组才是让 Hook 正确响应更新的关键。返回值Hook 返回一个用初始数据初始化好的共享值引用。该引用是一个带有.value属性的对象可以在 worklet 中被读取用于其他动画计算在主 JS 线程直接读取。但从类型定义看派生值是只读的。在 useDerivedValueCommon.ts 中DerivedValue被定义为export interface DerivedValueValue unknown extends Readonly OmitSharedValueValue, set { set: SharedValueValue[set]; // deprecated仅用于兼容既有类型 }即它继承SharedValue的只读形式并移除了set方法保留的set字段已被标记deprecated仅为防止 TypeScript 类型破坏未来会移除。对应的类型测试 useDerivedValueTest.tst.ts 验证了value被推断为{ readonly value: number }并且能自动从 updater 的返回类型推断出DerivedValuenumber。完整示例进度驱动的宽度派生官方文档提供了一个直观的实战示例定义一个取值范围 0 到 1 的progress共享值再用useDerivedValue派生出一个始终等于progress * 250的width共享值。import { Button } from react-native; import { useSharedValue, useDerivedValue } from react-native-reanimated; function App() { const progress useSharedValue(0); const width useDerivedValue(() { return progress.value * 250; }); return ( View SomeComponent width{width} / Button onPress{() (progress.value Math.random())} / /View ); }运行效果点击按钮会为progress赋一个 0~1 之间的随机数width的更新 worklet 立即被触发重新计算为progress.value * 250因此width永远与progress保持同步等于progress当前值乘以 250。这里width是共享值引用可以传给自定义组件如SomeComponent直接用于动画样式或 props。结合useAnimatedStyle的典型用法是useDerivedValue负责把多个共享值折叠成一个派生值而useAnimatedStyle只消费这个派生值从而让样式 worklet 保持简单、可复用。底层原理它是如何保持同步的useDerivedValue的同步能力并非魔法而是建立在 Reanimated 的mapper映射器机制之上。核心实现在 useDerivedValueCommon.ts可拆解为四步组装依赖将传入的dependencies或由闭包提取出的 inputs与updater.__workletHash拼接作为 ReactuseEffect的重建依据。初始化共享值通过makeMutable(initialUpdaterRun(updater))创建可变共享值并用initialUpdaterRun立即执行一次 updater 得到初始值。注册 mapper在useEffect中构造一个内部 workletsharedValue.value updater()调用startMapper(fun, inputs, [sharedValue])把它注册进 mapper 注册表——inputs是它订阅的源共享值第三个参数是输出目标。卸载清理effect 清理函数中调用stopMapper(mapperId)注销 mapper避免内存泄漏。Native 端 mapper 注册表的实现见 mappers.native.tsstartMapper会通过scheduleOnUI在 UI 线程创建/获取global.__mapperRegistry为 mapper 的每个输入共享值注册addListener回调任一输入共享值变化时mapper 被标记为dirty随后在动画帧驱动下重新执行 worklet将计算结果写回输出共享值。stopMapper则删除 mapper 并逐一removeListener。也就是说useDerivedValue本质上是在共享值之间建立了一条数据流管道源共享值inputs变化 → mapper 置脏 → UI 线程执行 updater → 派生共享值更新 → 下游useAnimatedStyle等消费方拿到新值渲染。整个链路都在 UI 线程完成不经过 React 重渲染因此派生计算是高性能且与帧同步的。最佳实践与注意事项用派生值而非手动同步当多个动画值之间存在数学关系如进度→宽度、滚动偏移→透明度时应优先用useDerivedValue声明式描述而不是在回调里手动set后者容易漏更新且难以维护。保持 updater 纯净updater 应只依赖传入的共享值与闭包变量并返回新值不要在其中产生副作用。Native 端不要手动传 dependencies显式传入会在开发模式触发警告且可能引入多余的 effect 重建依赖 Babel/SWC 插件自动追踪即可。Web 端无插件时需要 dependencies如果不使用 Babel/SWC 插件updater.__closure为空Web 实现会回退到dependencies作为输入此时务必手动传入依赖。不要对派生值写操作DerivedValue是只读的见类型测试对set的弃用说明如需可变值请改用useSharedValue。注意闭包变化默认省略 dependencies情况下worklet 体内引用的外部变量一旦变化就会触发重建若刻意忽略某闭包值可用空数组或显式依赖数组控制。延伸阅读手动管理共享值请参阅 useSharedValue 文档它定义了useDerivedValue返回引用的同款结构与.value读写方式。消费派生值渲染样式的官方文档useAnimatedStyle。深入源码Hook 入口 useDerivedValue.ts 与 useDerivedValue.native.ts、公共实现 useDerivedValueCommon.ts、mapper 注册表 mappers.native.ts、类型契约测试 useDerivedValueTest.tst.ts。【免费下载链接】react-native-reanimatedReact Natives Animated library reimplemented项目地址: https://gitcode.com/GitHub_Trending/re/react-native-reanimated创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考