Update Reanimated patch
This commit is contained in:
committed by
Oleksii Bulenok
parent
851220b3f9
commit
b82d7f5abc
@@ -1,16 +1,19 @@
|
|||||||
diff --git a/Common/cpp/reanimated/Fabric/updates/AnimatedPropsRegistry.cpp b/Common/cpp/reanimated/Fabric/updates/AnimatedPropsRegistry.cpp
|
diff --git a/Common/cpp/reanimated/Fabric/updates/AnimatedPropsRegistry.cpp b/Common/cpp/reanimated/Fabric/updates/AnimatedPropsRegistry.cpp
|
||||||
index 531f0dc7b4eeb9b29cb2255d8444da02a74c35b7..64a903157d8831fcf882c0d5198e777414808a27 100644
|
index 531f0dc7b4eeb9b29cb2255d8444da02a74c35b7..534f419fce55c39a09a7eebfb7ab3c53f8a16637 100644
|
||||||
--- a/Common/cpp/reanimated/Fabric/updates/AnimatedPropsRegistry.cpp
|
--- a/Common/cpp/reanimated/Fabric/updates/AnimatedPropsRegistry.cpp
|
||||||
+++ b/Common/cpp/reanimated/Fabric/updates/AnimatedPropsRegistry.cpp
|
+++ b/Common/cpp/reanimated/Fabric/updates/AnimatedPropsRegistry.cpp
|
||||||
@@ -2,6 +2,7 @@
|
@@ -1,8 +1,10 @@
|
||||||
|
#include <reanimated/Fabric/updates/AnimatedPropsRegistry.h>
|
||||||
#include <reanimated/Tools/FeatureFlags.h>
|
#include <reanimated/Tools/FeatureFlags.h>
|
||||||
|
|
||||||
|
+#include <functional>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
+#include <tuple>
|
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
+#include <vector>
|
||||||
|
|
||||||
namespace reanimated {
|
namespace reanimated {
|
||||||
@@ -25,7 +26,13 @@ void AnimatedPropsRegistry::update(jsi::Runtime &rt, const jsi::Value &operation
|
|
||||||
|
@@ -25,25 +27,59 @@ void AnimatedPropsRegistry::update(jsi::Runtime &rt, const jsi::Value &operation
|
||||||
addUpdatesToBatch(shadowNode, jsi::dynamicFromValue(rt, updates));
|
addUpdatesToBatch(shadowNode, jsi::dynamicFromValue(rt, updates));
|
||||||
|
|
||||||
if constexpr (StaticFeatureFlags::getFlag("FORCE_REACT_RENDER_FOR_SETTLED_ANIMATIONS")) {
|
if constexpr (StaticFeatureFlags::getFlag("FORCE_REACT_RENDER_FOR_SETTLED_ANIMATIONS")) {
|
||||||
@@ -18,69 +21,85 @@ index 531f0dc7b4eeb9b29cb2255d8444da02a74c35b7..64a903157d8831fcf882c0d5198e7774
|
|||||||
+ const auto tag = shadowNode->getTag();
|
+ const auto tag = shadowNode->getTag();
|
||||||
+ timestampMap_[tag] = timestamp;
|
+ timestampMap_[tag] = timestamp;
|
||||||
+ // If JS already has a `settledProps` snapshot for this tag, it is now
|
+ // If JS already has a `settledProps` snapshot for this tag, it is now
|
||||||
+ // stale — schedule a refresh on the next `getUpdatesOlderThanTimestamp`.
|
+ // stale — schedule a refresh on the next `collectSettledUpdates`.
|
||||||
+ if (syncedTags_.erase(tag) > 0) {
|
+ if (syncedTags_.erase(tag) > 0) {
|
||||||
+ invalidatedTags_.insert(tag);
|
+ invalidatedTags_.insert(tag);
|
||||||
+ }
|
+ }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -37,22 +44,40 @@ jsi::Value AnimatedPropsRegistry::getUpdatesOlderThanTimestamp(
|
|
||||||
|
-jsi::Value AnimatedPropsRegistry::getUpdatesOlderThanTimestamp(
|
||||||
|
- jsi::Runtime &rt,
|
||||||
|
- const double timestamp,
|
||||||
|
- const double cleanupTimestamp) {
|
||||||
|
+jsi::Value AnimatedPropsRegistry::collectSettledUpdates(jsi::Runtime &rt, const double settledTimestamp) {
|
||||||
std::lock_guard<std::mutex> lock{mutex_};
|
std::lock_guard<std::mutex> lock{mutex_};
|
||||||
removeUpdatesOlderThanTimestamp(cleanupTimestamp);
|
- removeUpdatesOlderThanTimestamp(cleanupTimestamp);
|
||||||
|
|
||||||
- std::vector<std::pair<Tag, std::reference_wrapper<const folly::dynamic>>> updates;
|
std::vector<std::pair<Tag, std::reference_wrapper<const folly::dynamic>>> updates;
|
||||||
+ // Each returned tag is paired with whether it came from the settled path —
|
|
||||||
+ // only settled-path tags are tracked as "synced" so that an ongoing animation
|
|
||||||
+ // doesn't re-trigger an invalidation/sync on every GC tick.
|
|
||||||
+ std::vector<std::tuple<Tag, std::reference_wrapper<const folly::dynamic>, bool>> updates;
|
|
||||||
|
|
||||||
for (const auto &[viewTag, pair] : updatesRegistry_) {
|
- for (const auto &[viewTag, pair] : updatesRegistry_) {
|
||||||
auto it = timestampMap_.find(viewTag);
|
- auto it = timestampMap_.find(viewTag);
|
||||||
- if (it != timestampMap_.end() && it->second < timestamp) {
|
- if (it != timestampMap_.end() && it->second < timestamp) {
|
||||||
- updates.emplace_back(viewTag, std::cref(pair.second));
|
- updates.emplace_back(viewTag, std::cref(pair.second));
|
||||||
+ if (it == timestampMap_.end()) {
|
+ for (auto it = updatesRegistry_.begin(); it != updatesRegistry_.end();) {
|
||||||
|
+ const auto viewTag = it->first;
|
||||||
|
+
|
||||||
|
+ if (syncedTags_.contains(viewTag)) {
|
||||||
|
+ // React already has the latest value for this tag (synced on a previous
|
||||||
|
+ // call, so the `settledProps` state is committed by now) — the registry
|
||||||
|
+ // entry is redundant. `syncedTags_` is intentionally retained to detect
|
||||||
|
+ // re-animation staleness. Note that `syncedTags_` and `invalidatedTags_`
|
||||||
|
+ // are disjoint — `update()` moves tags from the former to the latter.
|
||||||
|
+ timestampMap_.erase(viewTag);
|
||||||
|
+ it = updatesRegistry_.erase(it);
|
||||||
+ continue;
|
+ continue;
|
||||||
+ }
|
+ }
|
||||||
+ const bool isSettled = it->second < timestamp;
|
+
|
||||||
|
+ const auto timestampIt = timestampMap_.find(viewTag);
|
||||||
|
+ if (timestampIt == timestampMap_.end()) {
|
||||||
|
+ ++it;
|
||||||
|
+ continue;
|
||||||
|
+ }
|
||||||
|
+ const bool isSettled = timestampIt->second < settledTimestamp;
|
||||||
+ const auto invalidatedIt = invalidatedTags_.find(viewTag);
|
+ const auto invalidatedIt = invalidatedTags_.find(viewTag);
|
||||||
+ const bool isStaleSynced = invalidatedIt != invalidatedTags_.end();
|
+ const bool isInvalidated = invalidatedIt != invalidatedTags_.end();
|
||||||
+ if (isSettled || isStaleSynced) {
|
+ if (isSettled || isInvalidated) {
|
||||||
+ updates.emplace_back(viewTag, std::cref(pair.second), isSettled);
|
+ updates.emplace_back(viewTag, std::cref(it->second.second));
|
||||||
+ if (isStaleSynced) {
|
+ if (isSettled) {
|
||||||
|
+ // Only settled-path tags are tracked as "synced" so that an ongoing
|
||||||
|
+ // animation doesn't re-trigger an invalidation/sync on every GC tick.
|
||||||
|
+ syncedTags_.insert(viewTag);
|
||||||
|
+ }
|
||||||
|
+ if (isInvalidated) {
|
||||||
+ // Only erase serviced invalidations; if a tag was invalidated but the
|
+ // Only erase serviced invalidations; if a tag was invalidated but the
|
||||||
+ // matching update batch hasn't been flushed into updatesRegistry_ yet,
|
+ // matching update batch hasn't been flushed into updatesRegistry_ yet,
|
||||||
+ // we leave the entry so the next sync picks it up.
|
+ // we leave the entry so the next sync picks it up.
|
||||||
+ invalidatedTags_.erase(invalidatedIt);
|
+ invalidatedTags_.erase(invalidatedIt);
|
||||||
+ }
|
+ }
|
||||||
}
|
}
|
||||||
|
+ ++it;
|
||||||
}
|
}
|
||||||
|
|
||||||
const jsi::Array array(rt, updates.size());
|
const jsi::Array array(rt, updates.size());
|
||||||
size_t i = 0;
|
@@ -58,22 +94,11 @@ jsi::Value AnimatedPropsRegistry::getUpdatesOlderThanTimestamp(
|
||||||
- for (const auto &[viewTag, styleProps] : updates) {
|
|
||||||
+ for (const auto &[viewTag, styleProps, isSettled] : updates) {
|
|
||||||
const jsi::Object item(rt);
|
|
||||||
item.setProperty(rt, "viewTag", viewTag);
|
|
||||||
item.setProperty(rt, "styleProps", jsi::valueFromDynamic(rt, styleProps.get()));
|
|
||||||
array.setValueAtIndex(rt, i++, item);
|
|
||||||
+ if (isSettled) {
|
|
||||||
+ syncedTags_.insert(viewTag);
|
|
||||||
+ }
|
|
||||||
}
|
|
||||||
|
|
||||||
return jsi::Value(rt, array);
|
return jsi::Value(rt, array);
|
||||||
@@ -62,7 +87,8 @@ void AnimatedPropsRegistry::removeUpdatesOlderThanTimestamp(const double timesta
|
}
|
||||||
for (auto it = timestampMap_.begin(); it != timestampMap_.end();) {
|
|
||||||
const auto viewTag = it->first;
|
-void AnimatedPropsRegistry::removeUpdatesOlderThanTimestamp(const double timestamp) {
|
||||||
const auto viewTimestamp = it->second;
|
- for (auto it = timestampMap_.begin(); it != timestampMap_.end();) {
|
||||||
|
- const auto viewTag = it->first;
|
||||||
|
- const auto viewTimestamp = it->second;
|
||||||
- if (viewTimestamp < timestamp) {
|
- if (viewTimestamp < timestamp) {
|
||||||
+
|
- it = timestampMap_.erase(it);
|
||||||
+ if (viewTimestamp < timestamp && syncedTags_.count(viewTag) > 0) {
|
- updatesRegistry_.erase(viewTag);
|
||||||
it = timestampMap_.erase(it);
|
- } else {
|
||||||
updatesRegistry_.erase(viewTag);
|
- it++;
|
||||||
} else {
|
- }
|
||||||
@@ -74,6 +100,8 @@ void AnimatedPropsRegistry::removeUpdatesOlderThanTimestamp(const double timesta
|
- }
|
||||||
|
-}
|
||||||
|
-
|
||||||
void AnimatedPropsRegistry::removeTag(const Tag tag) {
|
void AnimatedPropsRegistry::removeTag(const Tag tag) {
|
||||||
updatesRegistry_.erase(tag);
|
updatesRegistry_.erase(tag);
|
||||||
timestampMap_.erase(tag);
|
timestampMap_.erase(tag);
|
||||||
@@ -90,29 +109,47 @@ index 531f0dc7b4eeb9b29cb2255d8444da02a74c35b7..64a903157d8831fcf882c0d5198e7774
|
|||||||
|
|
||||||
} // namespace reanimated
|
} // namespace reanimated
|
||||||
diff --git a/Common/cpp/reanimated/Fabric/updates/AnimatedPropsRegistry.h b/Common/cpp/reanimated/Fabric/updates/AnimatedPropsRegistry.h
|
diff --git a/Common/cpp/reanimated/Fabric/updates/AnimatedPropsRegistry.h b/Common/cpp/reanimated/Fabric/updates/AnimatedPropsRegistry.h
|
||||||
index 2c6c0e13604c9421e147d7eea7f4a4752288011c..da69e9119f200bb11878455232cf975f6f2c0042 100644
|
index 2c6c0e13604c9421e147d7eea7f4a4752288011c..8cd67f118501c2786b94d76541aea29a14ba8c16 100644
|
||||||
--- a/Common/cpp/reanimated/Fabric/updates/AnimatedPropsRegistry.h
|
--- a/Common/cpp/reanimated/Fabric/updates/AnimatedPropsRegistry.h
|
||||||
+++ b/Common/cpp/reanimated/Fabric/updates/AnimatedPropsRegistry.h
|
+++ b/Common/cpp/reanimated/Fabric/updates/AnimatedPropsRegistry.h
|
||||||
@@ -7,6 +7,7 @@
|
@@ -4,10 +4,8 @@
|
||||||
#include <memory>
|
|
||||||
#include <string>
|
#include <react/renderer/uimanager/UIManager.h>
|
||||||
|
|
||||||
|
-#include <memory>
|
||||||
|
-#include <string>
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
|
-#include <vector>
|
||||||
+#include <unordered_set>
|
+#include <unordered_set>
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
namespace reanimated {
|
namespace reanimated {
|
||||||
@@ -20,6 +21,11 @@ class AnimatedPropsRegistry : public UpdatesRegistry {
|
|
||||||
|
@@ -15,13 +13,22 @@ class AnimatedPropsRegistry : public UpdatesRegistry {
|
||||||
|
public:
|
||||||
|
void update(jsi::Runtime &rt, const jsi::Value &operations, double timestamp);
|
||||||
|
|
||||||
|
- /// Also removes updates older than `cleanupTimestamp` from the registry.
|
||||||
|
- jsi::Value getUpdatesOlderThanTimestamp(jsi::Runtime &rt, double timestamp, double cleanupTimestamp);
|
||||||
|
+ /// Returns updates that settled (received no update since `settledTimestamp`)
|
||||||
|
+ /// or whose synced `settledProps` snapshot was invalidated by a fresh update.
|
||||||
|
+ /// Also evicts entries that have already been synced to React — by the time
|
||||||
|
+ /// of the next call, the corresponding `settledProps` state is guaranteed to
|
||||||
|
+ /// be committed, so the registry entries are redundant.
|
||||||
|
+ jsi::Value collectSettledUpdates(jsi::Runtime &rt, double settledTimestamp);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::unordered_map<Tag, double> timestampMap_; // viewTag -> timestamp, protected by `mutex_`
|
std::unordered_map<Tag, double> timestampMap_; // viewTag -> timestamp, protected by `mutex_`
|
||||||
+ // Tags whose latest values have already been pushed to React `settledProps`.
|
+ // Tags whose latest values have already been pushed to React `settledProps`.
|
||||||
|
+ // Intentionally retained after eviction to detect re-animation staleness.
|
||||||
+ std::unordered_set<Tag> syncedTags_;
|
+ std::unordered_set<Tag> syncedTags_;
|
||||||
+ // Tags that were synced to React but received a fresh worklet update since;
|
+ // Tags that were synced to React but received a fresh worklet update since;
|
||||||
+ // their `settledProps` are stale and need to be refreshed on the next sync.
|
+ // their `settledProps` are stale and need to be refreshed on the next sync.
|
||||||
+ std::unordered_set<Tag> invalidatedTags_;
|
+ std::unordered_set<Tag> invalidatedTags_;
|
||||||
|
|
||||||
void removeUpdatesOlderThanTimestamp(double timestamp);
|
- void removeUpdatesOlderThanTimestamp(double timestamp);
|
||||||
void removeTag(Tag tag) override;
|
void removeTag(Tag tag) override;
|
||||||
|
};
|
||||||
|
|
||||||
diff --git a/Common/cpp/reanimated/LayoutAnimations/LayoutAnimationsProxyCommon.h b/Common/cpp/reanimated/LayoutAnimations/LayoutAnimationsProxyCommon.h
|
diff --git a/Common/cpp/reanimated/LayoutAnimations/LayoutAnimationsProxyCommon.h b/Common/cpp/reanimated/LayoutAnimations/LayoutAnimationsProxyCommon.h
|
||||||
index 096218ab9659955cd6272c97181bce3c893ed591..1a8e25fc8295b3ac943130709bf063ea41a50585 100644
|
index 096218ab9659955cd6272c97181bce3c893ed591..1a8e25fc8295b3ac943130709bf063ea41a50585 100644
|
||||||
--- a/Common/cpp/reanimated/LayoutAnimations/LayoutAnimationsProxyCommon.h
|
--- a/Common/cpp/reanimated/LayoutAnimations/LayoutAnimationsProxyCommon.h
|
||||||
@@ -367,10 +404,29 @@ index e9a5e9959e89ec33cee179ddb907c17f6dfbd3de..a2c89041518cd71e8ba5ac62ef89c002
|
|||||||
|
|
||||||
} // namespace reanimated
|
} // namespace reanimated
|
||||||
diff --git a/Common/cpp/reanimated/NativeModules/ReanimatedModuleProxy.cpp b/Common/cpp/reanimated/NativeModules/ReanimatedModuleProxy.cpp
|
diff --git a/Common/cpp/reanimated/NativeModules/ReanimatedModuleProxy.cpp b/Common/cpp/reanimated/NativeModules/ReanimatedModuleProxy.cpp
|
||||||
index 9ade22bf773005613048a00c47b35767628e86c6..688fdfb82715261fd08a63126c8691b0095fbf56 100644
|
index 9ade22bf773005613048a00c47b35767628e86c6..f3415e824da1a8da5c83762415ca54646bd6429f 100644
|
||||||
--- a/Common/cpp/reanimated/NativeModules/ReanimatedModuleProxy.cpp
|
--- a/Common/cpp/reanimated/NativeModules/ReanimatedModuleProxy.cpp
|
||||||
+++ b/Common/cpp/reanimated/NativeModules/ReanimatedModuleProxy.cpp
|
+++ b/Common/cpp/reanimated/NativeModules/ReanimatedModuleProxy.cpp
|
||||||
@@ -1306,11 +1306,11 @@ void ReanimatedModuleProxy::initializeLayoutAnimationsProxy() {
|
@@ -524,15 +524,13 @@ jsi::Value ReanimatedModuleProxy::getSettledUpdates(jsi::Runtime &rt) {
|
||||||
|
StaticFeatureFlags::getFlag("FORCE_REACT_RENDER_FOR_SETTLED_ANIMATIONS") &&
|
||||||
|
"getSettledUpdates requires FORCE_REACT_RENDER_FOR_SETTLED_ANIMATIONS static feature flag to be enabled");
|
||||||
|
|
||||||
|
+ constexpr double SETTLED_ANIMATION_THRESHOLD_MS = 1000;
|
||||||
|
+
|
||||||
|
// TODO(future): use unified timestamp
|
||||||
|
const auto currentTimestamp = getAnimationTimestamp_();
|
||||||
|
|
||||||
|
- // TODO: fix bug when threshold difference is smaller than 1 second
|
||||||
|
// TODO(future): flush updates from CSS animations and CSS transitions registries
|
||||||
|
- // TODO(future): find a better way to obtain timestamp for removing updates
|
||||||
|
- // TODO(future): move removing old updates to separate method
|
||||||
|
- return animatedPropsRegistry_->getUpdatesOlderThanTimestamp(
|
||||||
|
- rt, currentTimestamp - 1000 /* 1 second */, currentTimestamp - 2000 /* 2 seconds */);
|
||||||
|
+ return animatedPropsRegistry_->collectSettledUpdates(rt, currentTimestamp - SETTLED_ANIMATION_THRESHOLD_MS);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ReanimatedModuleProxy::handleEvent(
|
||||||
|
@@ -1306,11 +1304,11 @@ void ReanimatedModuleProxy::initializeLayoutAnimationsProxy() {
|
||||||
componentDescriptorRegistry,
|
componentDescriptorRegistry,
|
||||||
scheduler->getContextContainer(),
|
scheduler->getContextContainer(),
|
||||||
getJSIRuntimeFromWorkletRuntime(uiRuntime_),
|
getJSIRuntimeFromWorkletRuntime(uiRuntime_),
|
||||||
@@ -384,7 +440,7 @@ index 9ade22bf773005613048a00c47b35767628e86c6..688fdfb82715261fd08a63126c8691b0
|
|||||||
jsInvoker_
|
jsInvoker_
|
||||||
#endif
|
#endif
|
||||||
);
|
);
|
||||||
@@ -1319,22 +1319,19 @@ void ReanimatedModuleProxy::initializeLayoutAnimationsProxy() {
|
@@ -1319,22 +1317,19 @@ void ReanimatedModuleProxy::initializeLayoutAnimationsProxy() {
|
||||||
#endif
|
#endif
|
||||||
layoutAnimationsProxy_ = std::move(layoutAnimationsProxyExperimental);
|
layoutAnimationsProxy_ = std::move(layoutAnimationsProxyExperimental);
|
||||||
} else {
|
} else {
|
||||||
@@ -410,3 +466,35 @@ index 9ade22bf773005613048a00c47b35767628e86c6..688fdfb82715261fd08a63126c8691b0
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
diff --git a/src/PropsRegistryGarbageCollector.ts b/src/PropsRegistryGarbageCollector.ts
|
||||||
|
index f917ce5a8586c02855f1d8d9ae73154592d22510..32148fbac8a9224ffec6edc784b48938da9585fb 100644
|
||||||
|
--- a/src/PropsRegistryGarbageCollector.ts
|
||||||
|
+++ b/src/PropsRegistryGarbageCollector.ts
|
||||||
|
@@ -11,7 +11,6 @@ import { ReanimatedModule } from './ReanimatedModule';
|
||||||
|
const FLUSH_INTERVAL_MS = 500;
|
||||||
|
|
||||||
|
export const PropsRegistryGarbageCollector = {
|
||||||
|
- viewsCount: 0,
|
||||||
|
viewsMap: new Map<number, IAnimatedComponentInternal>(),
|
||||||
|
intervalId: null as NodeJS.Timeout | null,
|
||||||
|
|
||||||
|
@@ -25,16 +24,14 @@ export const PropsRegistryGarbageCollector = {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.viewsMap.set(viewTag, component);
|
||||||
|
- this.viewsCount++;
|
||||||
|
- if (this.viewsCount === 1) {
|
||||||
|
+ if (this.viewsMap.size === 1) {
|
||||||
|
this.registerInterval();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
unregisterView(viewTag: number) {
|
||||||
|
- this.viewsMap.delete(viewTag);
|
||||||
|
- this.viewsCount--;
|
||||||
|
- if (this.viewsCount === 0) {
|
||||||
|
+ const deleted = this.viewsMap.delete(viewTag);
|
||||||
|
+ if (deleted && this.viewsMap.size === 0) {
|
||||||
|
this.unregisterInterval();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|||||||
@@ -1,10 +1,9 @@
|
|||||||
# react-native-reanimated@4.3.2.patch
|
# react-native-reanimated@4.3.2.patch
|
||||||
|
|
||||||
Contains two independent changes:
|
Backports of two merged upstream PRs:
|
||||||
|
|
||||||
1. Backport of PR 9901 (`LayoutAnimation.configureNext` compatibility)
|
1. PR 9901 (`LayoutAnimation.configureNext` compatibility)
|
||||||
2. Backport of PR 9527 plus an eviction guard in `AnimatedPropsRegistry`
|
2. PR 9971 (stale `settledProps` on worklet re-animation / after app resume)
|
||||||
(stale `settledProps` applied after app resume)
|
|
||||||
|
|
||||||
## 1. Backport of PR 9901
|
## 1. Backport of PR 9901
|
||||||
|
|
||||||
@@ -29,33 +28,38 @@ Only the `packages/react-native-reanimated` part of the PR is included (the
|
|||||||
include hunk in `LayoutAnimationsProxy_Legacy.cpp` was adjusted to the 4.3.2
|
include hunk in `LayoutAnimationsProxy_Legacy.cpp` was adjusted to the 4.3.2
|
||||||
release sources.
|
release sources.
|
||||||
|
|
||||||
## 2. Stale `settledProps` after app resume (AnimatedPropsRegistry)
|
## 2. Backport of PR 9971 (stale `settledProps`)
|
||||||
|
|
||||||
Backport of https://github.com/software-mansion/react-native-reanimated/pull/9527
|
Verbatim application of
|
||||||
("Fix stale settledProps on worklet re-animation") plus an additional eviction
|
https://github.com/software-mansion/react-native-reanimated/pull/9971, the
|
||||||
guard on top of it. Fixes the Android DM composer "phantom jump"
|
4.3-stable cherry-pick of
|
||||||
|
https://github.com/software-mansion/react-native-reanimated/pull/9527
|
||||||
|
("Fix stale settledProps on worklet re-animation"). Fixes the Android DM
|
||||||
|
composer "phantom jump"
|
||||||
(https://github.com/software-mansion/react-native-reanimated/issues/9574).
|
(https://github.com/software-mansion/react-native-reanimated/issues/9574).
|
||||||
|
|
||||||
Background: with `FORCE_REACT_RENDER_FOR_SETTLED_ANIMATIONS`, once an
|
Background: with `FORCE_REACT_RENDER_FOR_SETTLED_ANIMATIONS`, once an
|
||||||
animation settles its final props are handed to JS (polled every 500 ms by
|
animation settles its final props are handed to JS (polled every 500 ms by
|
||||||
`PropsRegistryGarbageCollector`) and stored in React component state
|
`PropsRegistryGarbageCollector`) and stored in React component state
|
||||||
(`settledProps`). The native registry entry is then evicted ~2 s after the
|
(`settledProps`), after which the React-side snapshot becomes the sole owner
|
||||||
last worklet write, at which point `ReanimatedCommitHook` no longer covers the
|
of the value.
|
||||||
view and the React-side snapshot becomes the sole owner of the value.
|
|
||||||
|
|
||||||
The PR 9527 part adds `syncedTags_` / `invalidatedTags_` so that when a
|
The PR replaces `getUpdatesOlderThanTimestamp` (which evicted registry
|
||||||
previously-synced view re-animates, its now-stale React snapshot is refreshed
|
entries on a wall-clock 1 s/2 s window) with `collectSettledUpdates`:
|
||||||
on the next GC tick instead of waiting up to ~1.5 s for the new value to
|
|
||||||
settle.
|
|
||||||
|
|
||||||
The additional guard fixes the handoff itself. Upstream, eviction relies on a
|
- `syncedTags_` / `invalidatedTags_` track which tags React already has a
|
||||||
timing assumption: the settled value is returnable between 1 s and 2 s of age,
|
snapshot for; when a previously-synced view re-animates, its stale snapshot
|
||||||
and a 500 ms JS timer is assumed to tick inside that window. If no tick lands
|
is refreshed on the next GC tick instead of waiting for the new value to
|
||||||
there (app backgrounded while a keyboard-driven animation finishes, JS thread
|
settle.
|
||||||
blocked for >1 s), the first tick after resume destroys the entry inside
|
- Eviction is no longer time-based. An entry is only evicted on the tick
|
||||||
`getUpdatesOlderThanTimestamp` *before* the collection loop can return it -
|
*after* it was returned to JS (once its `settledProps` commit is
|
||||||
the settled value is lost, React state keeps the pre-background value, and the
|
guaranteed), so a missed timer window (app backgrounded, JS thread blocked)
|
||||||
next React commit snaps the view back (the phantom jump). The guard makes
|
can no longer destroy a settled value before it reaches React. This
|
||||||
`removeUpdatesOlderThanTimestamp` only evict tags present in `syncedTags_`,
|
replaces the ad-hoc eviction guard an earlier version of this patch added
|
||||||
i.e. values that were actually handed to JS; an unsynced stale entry survives
|
on top of the pre-merge PR 9527.
|
||||||
one more tick, gets returned as settled, and is evicted on the following tick.
|
- `PropsRegistryGarbageCollector` drops the separate `viewsCount` counter
|
||||||
|
(which could desync when nested animated components unregister a tag that
|
||||||
|
was never registered, stopping the GC interval while views remain) in favor
|
||||||
|
of `viewsMap.size`. Only `src/` is touched, matching the PR; Metro bundles
|
||||||
|
the app from `src/` via the package's `react-native` field, and the stale
|
||||||
|
`lib/` copy is unreachable (the feature is native-only).
|
||||||
|
|||||||
Reference in New Issue
Block a user