-
Notifications
You must be signed in to change notification settings - Fork 24.3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
fix: Patch AnimatedStyle to avoid discarding the initial style info #35198
fix: Patch AnimatedStyle to avoid discarding the initial style info #35198
Conversation
Base commit: e504141 |
Base commit: e504141 |
PR build artifact for bdc9819 is ready. |
Please provide a unit tests that shows how this behaviour was broken before and how this change resolves it. This will help me understand the goal here and prevent us from breaking it in the future :) |
@necolas would you mind helping me with this one? I know that the problem is described on necolas/react-native-web#2387 but I'm not completely sure how to recreate that scenario on this repo |
_style: Object; | ||
|
||
constructor(style: any) { | ||
super(); | ||
style = flattenStyle(style) || ({}: {[string]: any}); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
On web, using flattenStyle
creates a new object each time which causes correctness and perf issues:
- It mixes inline and compiled styles into a single object.
- The style runtime can no longer recognize the style object as static / pre-compiled.
- The style runtime can no longer cache the result of style merges involving this style.
function createAnimatedStyle(inputStyle: any): Object { | ||
const style = flattenStyle(inputStyle); | ||
const animatedStyles: any = {}; | ||
for (const key in style) { | ||
const value = style[key]; | ||
if (key === 'transform') { | ||
animatedStyles[key] = new AnimatedTransform(value); | ||
} else if (value instanceof AnimatedNode) { | ||
animatedStyles[key] = value; | ||
} else if (value && !Array.isArray(value) && typeof value === 'object') { | ||
animatedStyles[key] = createAnimatedStyle(value); | ||
} | ||
} | ||
return animatedStyles; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since Animated nodes can only exist on inline styles, this function plucks them out of the provided styles and places them into a separate object that can be appended to the original input styles.
The behavior is broken on web because using A unit test for this change in RN would only show that Animated nodes are duplicated in a new style object appended to the input styles, and that the return from the Style node is an array instead of an object. There would be no functional difference on native. |
bdc9819
to
c47a9f4
Compare
PR build artifact for c47a9f4 is ready. |
ba6f59d
to
c45bf58
Compare
PR build artifact for c45bf58 is ready. |
92af6c4
to
b45837a
Compare
PR build artifact for b45837a is ready. |
Does this correctly handle scenarios like this?
The expected outcome would be that |
Yes, it does. The first thing we do is a flatten, and then extract any animated values that are left |
6999082
to
45e8c02
Compare
PR build artifact for 45e8c02 is ready. |
@necolas FYI this should be good for another review round |
it('does not discard initial style', () => { | ||
const value1 = new Animated.Value(1); | ||
const scale = value1.interpolate({ | ||
inputRange: [0, 1], | ||
outputRange: [1, 2], | ||
}); | ||
const callback = jest.fn(); | ||
const node = new AnimatedProps( | ||
{ | ||
style: { | ||
transform: [ | ||
{ | ||
scale, | ||
}, | ||
], | ||
}, | ||
}, | ||
callback, | ||
); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This test will be a bit confusing without changes / explanation. The behavior matters when the input style is a mix of values from StyleSheet.create
(ie contains no animated values, could be optimized to another format) and an inline style with an animation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sounds good, I've updated tests a bit to include StyleSheet.create
PR build artifact for 5b6fede is ready. |
PR build artifact for 650c45e is ready. |
PR build artifact for 11daeda is ready. |
Hi @cipolleschi, do you mind importing this PR? 😅 |
@javache has imported this pull request. If you are a Meta employee, you can view this diff on Phabricator. |
…acebook#35198) Summary: This PR patches `AnimatedStyle` to avoid discarding the initial style information which destroys the output of web-style compilers and breaks rendering, as requested on facebook#34425. This uses a slightly modified version of a patch used by react-native-web necolas/react-native-web@4c678d2. ## Changelog [General] [Fixed] - Patch AnimatedStyle to avoid discarding the initial style info Pull Request resolved: facebook#35198 Test Plan: Run `yarn jest Animated` and ensure CI is green ![image](https://user-images.githubusercontent.com/11707729/199869612-4f2302da-5791-492f-83a7-683305757c23.png) Reviewed By: necolas Differential Revision: D41379826 Pulled By: javache fbshipit-source-id: 7e16726828b98def14847ec3499ff93777a9cbfb
…41176) Summary: #35198 introduced a regression where if an `{transform: undefined}` style is provided to an Animated View a `Cannot read property 'map' of undefined` type error is thrown <img src="https://github.com/facebook/react-native/assets/11707729/bb87781e-1ba7-40ec-879d-a57cef3e10d9" height="200" /> ## Changelog: [GENERAL] [FIXED] - Fix `createAnimatedStyle` when providing an undefined transform style Pull Request resolved: #41176 Test Plan: <details> <summary>Render an `Animated.View` passing `style={{transform: undefined}}`</summary> E.g. ``` const UndefinedTransform = () => { return ( <View> <Animated.View style={{transform: undefined}} /> </View> ); }; ``` </details> ### RNTester 1. Open the RNTester app and navigate to the Animated page 2. Navigate to the Transform Styles page 3. App should not throw any errors <table> <tr><th>Before</th><th>After</th></tr> <tr> <td><video src="https://github.com/facebook/react-native/assets/11707729/92ba9c3b-60b0-4805-8080-0e7fb7c00345"/></td> <td><video src="https://github.com/facebook/react-native/assets/11707729/80e2bba8-6ff6-4cf5-bcb8-26de0b869036"/></td> </tr> </table> Reviewed By: fabriziocucci Differential Revision: D50638415 Pulled By: javache fbshipit-source-id: 0ee949f019a77b8bef557888694e0e8404810105
…acebook#41176) Summary: facebook#35198 introduced a regression where if an `{transform: undefined}` style is provided to an Animated View a `Cannot read property 'map' of undefined` type error is thrown <img src="https://github.com/facebook/react-native/assets/11707729/bb87781e-1ba7-40ec-879d-a57cef3e10d9" height="200" /> ## Changelog: [GENERAL] [FIXED] - Fix `createAnimatedStyle` when providing an undefined transform style Pull Request resolved: facebook#41176 Test Plan: <details> <summary>Render an `Animated.View` passing `style={{transform: undefined}}`</summary> E.g. ``` const UndefinedTransform = () => { return ( <View> <Animated.View style={{transform: undefined}} /> </View> ); }; ``` </details> ### RNTester 1. Open the RNTester app and navigate to the Animated page 2. Navigate to the Transform Styles page 3. App should not throw any errors <table> <tr><th>Before</th><th>After</th></tr> <tr> <td><video src="https://github.com/facebook/react-native/assets/11707729/92ba9c3b-60b0-4805-8080-0e7fb7c00345"/></td> <td><video src="https://github.com/facebook/react-native/assets/11707729/80e2bba8-6ff6-4cf5-bcb8-26de0b869036"/></td> </tr> </table> Reviewed By: fabriziocucci Differential Revision: D50638415 Pulled By: javache fbshipit-source-id: 0ee949f019a77b8bef557888694e0e8404810105
…41176) Summary: #35198 introduced a regression where if an `{transform: undefined}` style is provided to an Animated View a `Cannot read property 'map' of undefined` type error is thrown <img src="https://github.com/facebook/react-native/assets/11707729/bb87781e-1ba7-40ec-879d-a57cef3e10d9" height="200" /> ## Changelog: [GENERAL] [FIXED] - Fix `createAnimatedStyle` when providing an undefined transform style Pull Request resolved: #41176 Test Plan: <details> <summary>Render an `Animated.View` passing `style={{transform: undefined}}`</summary> E.g. ``` const UndefinedTransform = () => { return ( <View> <Animated.View style={{transform: undefined}} /> </View> ); }; ``` </details> ### RNTester 1. Open the RNTester app and navigate to the Animated page 2. Navigate to the Transform Styles page 3. App should not throw any errors <table> <tr><th>Before</th><th>After</th></tr> <tr> <td><video src="https://github.com/facebook/react-native/assets/11707729/92ba9c3b-60b0-4805-8080-0e7fb7c00345"/></td> <td><video src="https://github.com/facebook/react-native/assets/11707729/80e2bba8-6ff6-4cf5-bcb8-26de0b869036"/></td> </tr> </table> Reviewed By: fabriziocucci Differential Revision: D50638415 Pulled By: javache fbshipit-source-id: 0ee949f019a77b8bef557888694e0e8404810105
Summary
This PR patches
AnimatedStyle
to avoid discarding the initial style information which destroys the output of web-style compilers and breaks rendering, as requested on #34425. This uses a slightly modified version of a patch used by react-native-web necolas/react-native-web@4c678d2.Changelog
[General] [Fixed] - Patch AnimatedStyle to avoid discarding the initial style info
Test Plan
Run
yarn jest Animated
and ensure CI is green