mirror of
https://github.com/facebook/react-native.git
synced 2025-11-01 09:14:26 +00:00
Add Fantom test for layout props & fix an issue in c++ animated (#52110)
Summary: Pull Request resolved: https://github.com/facebook/react-native/pull/52110 ## Changelog: [General] [Internal] - Add Fantom test for layout props With this test it turns out `layoutStyleUpdated_` on PropsAnimatedNode actually can change after animation update, because its connected StyleAnimatedNodes might be changing. This bug was introduced since D74602321 Reviewed By: rshest Differential Revision: D76753864 fbshipit-source-id: 5bebb11340086390df20c89adf80abaa63cadc90
This commit is contained in:
committed by
Facebook GitHub Bot
parent
cc442eb8c8
commit
710e08cd54
@@ -17,6 +17,7 @@ import ensureInstance from '../../../src/private/__tests__/utilities/ensureInsta
|
||||
import * as Fantom from '@react-native/fantom';
|
||||
import {createRef} from 'react';
|
||||
import {Animated, View, useAnimatedValue} from 'react-native';
|
||||
import {allowStyleProp} from 'react-native/Libraries/Animated/NativeAnimatedAllowlist';
|
||||
import * as ReactNativeFeatureFlags from 'react-native/src/private/featureflags/ReactNativeFeatureFlags';
|
||||
import ReactNativeElement from 'react-native/src/private/webapis/dom/nodes/ReactNativeElement';
|
||||
|
||||
@@ -152,6 +153,7 @@ test('animation driven by onScroll event', () => {
|
||||
|
||||
test('animated opacity', () => {
|
||||
let _opacity;
|
||||
let _opacityAnimation;
|
||||
const viewRef = createRef<HostInstance>();
|
||||
|
||||
function MyApp() {
|
||||
@@ -182,7 +184,7 @@ test('animated opacity', () => {
|
||||
expect(viewElement.getBoundingClientRect().x).toBe(0);
|
||||
|
||||
Fantom.runTask(() => {
|
||||
Animated.timing(_opacity, {
|
||||
_opacityAnimation = Animated.timing(_opacity, {
|
||||
toValue: 0,
|
||||
duration: 30,
|
||||
useNativeDriver: true,
|
||||
@@ -194,8 +196,10 @@ test('animated opacity', () => {
|
||||
0,
|
||||
);
|
||||
|
||||
// TODO(T223344928): this shouldn't be neccessary with cxxNativeAnimatedRemoveJsSync:true
|
||||
Fantom.runWorkLoop();
|
||||
// TODO: this shouldn't be neccessary since animation should be stopped after duration
|
||||
Fantom.runTask(() => {
|
||||
_opacityAnimation?.stop();
|
||||
});
|
||||
|
||||
expect(root.getRenderedOutput({props: ['opacity']}).toJSX()).toEqual(
|
||||
<rn-view opacity="0" />,
|
||||
@@ -475,3 +479,61 @@ describe('Value.extractOffset', () => {
|
||||
Fantom.runWorkLoop();
|
||||
});
|
||||
});
|
||||
|
||||
test('animate layout props', () => {
|
||||
const viewRef = createRef<HostInstance>();
|
||||
allowStyleProp('height');
|
||||
|
||||
let _animatedHeight;
|
||||
let _heightAnimation;
|
||||
|
||||
function MyApp() {
|
||||
const animatedHeight = useAnimatedValue(0);
|
||||
_animatedHeight = animatedHeight;
|
||||
return (
|
||||
<Animated.View
|
||||
ref={viewRef}
|
||||
style={[
|
||||
{
|
||||
width: 100,
|
||||
height: animatedHeight,
|
||||
},
|
||||
]}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
const root = Fantom.createRoot();
|
||||
|
||||
Fantom.runTask(() => {
|
||||
root.render(<MyApp />);
|
||||
});
|
||||
|
||||
const viewElement = ensureInstance(viewRef.current, ReactNativeElement);
|
||||
|
||||
Fantom.runTask(() => {
|
||||
_heightAnimation = Animated.timing(_animatedHeight, {
|
||||
toValue: 100,
|
||||
duration: 10,
|
||||
useNativeDriver: true,
|
||||
}).start();
|
||||
});
|
||||
|
||||
Fantom.unstable_produceFramesForDuration(10);
|
||||
|
||||
// TODO: this shouldn't be neccessary since animation should be stopped after duration
|
||||
Fantom.runTask(() => {
|
||||
_heightAnimation?.stop();
|
||||
});
|
||||
|
||||
// $FlowFixMe[incompatible-use]
|
||||
expect(Fantom.unstable_getDirectManipulationProps(viewElement).height).toBe(
|
||||
100,
|
||||
);
|
||||
|
||||
expect(Fantom.unstable_getFabricUpdateProps(viewElement).height).toBe(100);
|
||||
|
||||
expect(root.getRenderedOutput({props: ['height']}).toJSX()).toEqual(
|
||||
<rn-view height="100.000000" />,
|
||||
);
|
||||
});
|
||||
|
||||
+5
-10
@@ -12,7 +12,6 @@
|
||||
#include "PropsAnimatedNode.h"
|
||||
|
||||
#include <react/debug/react_native_assert.h>
|
||||
#include <react/renderer/animated/NativeAnimatedAllowlist.h>
|
||||
#include <react/renderer/animated/NativeAnimatedNodesManager.h>
|
||||
#include <react/renderer/animated/nodes/ColorAnimatedNode.h>
|
||||
#include <react/renderer/animated/nodes/StyleAnimatedNode.h>
|
||||
@@ -31,12 +30,8 @@ bool isLayoutStyleUpdated(
|
||||
if (node->type() == AnimatedNodeType::Style) {
|
||||
if (const auto& styleNode =
|
||||
manager.getAnimatedNode<StyleAnimatedNode>(nodeTag)) {
|
||||
auto& styleNodeProps = styleNode->getProps();
|
||||
for (const auto& styleNodeProp : styleNodeProps.items()) {
|
||||
if (getDirectManipulationAllowlist().count(
|
||||
styleNodeProp.first.asString()) == 0u) {
|
||||
return true;
|
||||
}
|
||||
if (styleNode->isLayoutStyleUpdated()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -53,9 +48,7 @@ PropsAnimatedNode::PropsAnimatedNode(
|
||||
const folly::dynamic& config,
|
||||
NativeAnimatedNodesManager& manager)
|
||||
: AnimatedNode(tag, config, manager, AnimatedNodeType::Props),
|
||||
props_(folly::dynamic::object()),
|
||||
layoutStyleUpdated_(isLayoutStyleUpdated(getConfig()["props"], manager)) {
|
||||
}
|
||||
props_(folly::dynamic::object()) {}
|
||||
|
||||
void PropsAnimatedNode::connectToView(Tag viewTag) {
|
||||
react_native_assert(
|
||||
@@ -145,6 +138,8 @@ void PropsAnimatedNode::update(bool forceFabricCommit) {
|
||||
}
|
||||
}
|
||||
|
||||
layoutStyleUpdated_ = isLayoutStyleUpdated(getConfig()["props"], *manager_);
|
||||
|
||||
manager_->schedulePropsCommit(
|
||||
connectedViewTag_, props_, layoutStyleUpdated_, forceFabricCommit);
|
||||
}
|
||||
|
||||
+1
-1
@@ -43,7 +43,7 @@ class PropsAnimatedNode final : public AnimatedNode {
|
||||
private:
|
||||
std::mutex propsMutex_;
|
||||
folly::dynamic props_;
|
||||
const bool layoutStyleUpdated_;
|
||||
bool layoutStyleUpdated_{false};
|
||||
|
||||
Tag connectedViewTag_{animated::undefinedAnimatedNodeIdentifier};
|
||||
};
|
||||
|
||||
+20
@@ -11,12 +11,29 @@
|
||||
|
||||
#include "StyleAnimatedNode.h"
|
||||
|
||||
#include <react/renderer/animated/NativeAnimatedAllowlist.h>
|
||||
#include <react/renderer/animated/NativeAnimatedNodesManager.h>
|
||||
#include <react/renderer/animated/nodes/ColorAnimatedNode.h>
|
||||
#include <react/renderer/animated/nodes/TransformAnimatedNode.h>
|
||||
#include <react/renderer/animated/nodes/ValueAnimatedNode.h>
|
||||
|
||||
namespace facebook::react {
|
||||
|
||||
namespace {
|
||||
|
||||
bool isLayoutPropsUpdated(const folly::dynamic& props) {
|
||||
for (const auto& styleNodeProp : props.items()) {
|
||||
if (getDirectManipulationAllowlist().count(
|
||||
styleNodeProp.first.asString()) == 0u) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
StyleAnimatedNode::StyleAnimatedNode(
|
||||
Tag tag,
|
||||
const folly::dynamic& config,
|
||||
@@ -77,5 +94,8 @@ void StyleAnimatedNode::update() {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
layoutStyleUpdated_ = isLayoutPropsUpdated(props_);
|
||||
}
|
||||
|
||||
} // namespace facebook::react
|
||||
|
||||
+5
@@ -28,7 +28,12 @@ class StyleAnimatedNode final : public AnimatedNode {
|
||||
return props_;
|
||||
}
|
||||
|
||||
bool isLayoutStyleUpdated() const noexcept {
|
||||
return layoutStyleUpdated_;
|
||||
}
|
||||
|
||||
private:
|
||||
folly::dynamic props_;
|
||||
bool layoutStyleUpdated_;
|
||||
};
|
||||
} // namespace facebook::react
|
||||
|
||||
Reference in New Issue
Block a user