Skip to content
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

Opacity in TouchableOpacity properly react to state change #32956

Closed
wants to merge 10 commits into from

Conversation

hetanthakkar
Copy link
Contributor

Summary

This PR fixes the opacity bug where it fails to properly react to state change. This PR resolves the issue detailed in #32476

Changelog

[General] [Fixed] - Fixed opacity value in TouchableOpacity

Test Plan

The code I added in componentDidUpdate does solve the issue and passes all the test cases

@facebook-github-bot facebook-github-bot added CLA Signed This label is managed by the Facebook bot. Authors need to sign the CLA before a PR can be reviewed. Shared with Meta Applied via automation to indicate that an Issue or Pull Request has been shared with the team. labels Jan 23, 2022
@hetanthakkar
Copy link
Contributor Author

This is a continuation of PR 32477.

I don’t think componendidupdate will cause additional rerender because it's calling Animate.Timing and I think that Animated.Timing doesn't cause rerender each time it updates state. I verified it by console logging a statement in render method and got to know that this approach doesn’t causes additional re-renders

@analysis-bot
Copy link

analysis-bot commented Jan 23, 2022

Platform Engine Arch Size (bytes) Diff
ios - universal n/a --

Base commit: ea74c57
Branch: main

if (this.props.disabled !== prevProps.disabled) {
if (
this.props.disabled !== prevProps.disabled ||
this.props.style !== prevProps.style
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One question, wouldn't this be true if inline styles were provided?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@gabrieldonadel This would be true only if the component recieved styles which are different than the previous/existing style

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry for not being clear, my question is regarding the shallow comparison between props.style and prevProps.style. If the user provides inline styles, e.g. <TouchableOpacity style={{backgroundColor:'blue'}}/> this if statement would always be true when a rerender occurs in the parent component, thus triggering _opacityInactive

image

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@gabrieldonadel Now does it look good?

@analysis-bot
Copy link

analysis-bot commented Jan 23, 2022

Platform Engine Arch Size (bytes) Diff
android hermes arm64-v8a 8,300,483 +81
android hermes armeabi-v7a 7,639,031 +89
android hermes x86 8,775,929 +81
android hermes x86_64 8,712,830 +73
android jsc arm64-v8a 9,784,841 +6
android jsc armeabi-v7a 8,770,731 +10
android jsc x86 9,751,476 +16
android jsc x86_64 10,347,644 +17

Base commit: ea74c57
Branch: main

Comment on lines 263 to 264
//function to check equality of two objects

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this comment is no longer necessary

Suggested change
//function to check equality of two objects

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@gabrieldonadel Done! Anything else I need to do?

@facebook-github-bot
Copy link
Contributor

@cortinico has imported this pull request. If you are a Meta employee, you can view this diff on Phabricator.

@hetanthakkar
Copy link
Contributor Author

@cortinico Can you please tell me what’s failing the test

@cortinico
Copy link
Contributor

@cortinico Can you please tell me what’s failing the test

I don't think it's related to your change. Let me take a closer look and get back to you

@cortinico
Copy link
Contributor

@cortinico Can you please review!?

Sorry but we're having an internal discussion that is taking a bit longer than expected.
Also, please don't comment on other unrelated PRs. As a rule of thumb, please refrain from directly pinging other users more than say once a week.

@ryancat expressed some concerns. Let me get back to you

@hetanthakkar
Copy link
Contributor Author

@cortinico Can you please review!?

Sorry but we're having an internal discussion that is taking a bit longer than expected. Also, please don't comment on other unrelated PRs. As a rule of thumb, please refrain from directly pinging other users more than say once a week.

@ryancat expressed some concerns. Let me get back to you

@cortinico Okay i get it will keep that in mind next time

if (this.props.disabled !== prevProps.disabled) {
if (
this.props.disabled !== prevProps.disabled ||
JSON.stringify(prevProps.style) !== JSON.stringify(this.props.style)
Copy link
Contributor

@Krisztiaan Krisztiaan Jan 28, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You could also just check if opacity is defined in style, and skip the change, without having to stringify for simple comparison

Suggested change
JSON.stringify(prevProps.style) !== JSON.stringify(this.props.style)
flattenStyle(this.props.style)?.opacity !== undefined

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Or maybe even

Suggested change
JSON.stringify(prevProps.style) !== JSON.stringify(this.props.style)
flattenStyle(prevProps.style)?.opacity !== flattenStyle(this.props.style)?.opacity !== undefined

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Krisztiaan Thank you! I changed it. @cortinico You can also see the new changes and consider that for your discussion.

@facebook-github-bot
Copy link
Contributor

@cortinico has imported this pull request. If you are a Meta employee, you can view this diff on Phabricator.

@ryancat
Copy link
Contributor

ryancat commented Jan 31, 2022

The problem here is a timing issue. When pressout, we already tried to reset active state here. However, that wasn't working properly as the _getChildStyleOpacityWithDefault() method still returns old opacity value from prop (expect 1, saw 0.1). The style prop is not updated until later.

We could've done this via UNSAFE_componentWillReceiveProps, or getDerivedStateFromProps, but neither of them are proper here. In fact, I believe the previous PR which checks only the opacity is better. I failed to follow up with that PR (Sorry! The notification setup on github has some issues and I failed to receive them on time), but after some thoughts, I think what he did makes sense.

From React doc:
If you need to perform a side effect (for example, data fetching or an animation) in response to a change in props, use componentDidUpdate lifecycle instead.

The author was correct that no extra re-render is expected from the change as we are using native driver.

Unless there are something else I didn't notice that changed in this PR, I suggest we go with the old PR's change.

@hetanthakkar
Copy link
Contributor Author

hetanthakkar commented Jan 31, 2022

The problem here is a timing issue. When pressout, we already tried to reset active state here. However, that wasn't working properly as the _getChildStyleOpacityWithDefault() method still returns old opacity value from prop (expect 1, saw 0.1). The style prop is not updated until later.

We could've done this via UNSAFE_componentWillReceiveProps, or getDerivedStateFromProps, but neither of them are proper here. In fact, I believe the previous PR which checks only the opacity is better. I failed to follow up with that PR (Sorry! The notification setup on github has some issues and I failed to receive them on time), but after some thoughts, I think what he did makes sense.

From React doc: If you need to perform a side effect (for example, data fetching or an animation) in response to a change in props, use componentDidUpdate lifecycle instead.

The author was correct that no extra re-render is expected from the change as we are using native driver.

Unless there are something else I didn't notice that changed in this PR, I suggest we go with the old PR's change.

@ryancat That is what I have done in this PR, comparing the opacity values in componentDidUpdate

@hetanthakkar
Copy link
Contributor Author

In my old PR doing this will fail tests: this.props.style.opacity !== prevProps.style.opacity because opacity is not accessible under styles So i have first flattened the styles and then compared the opacity

@Krisztiaan
Copy link
Contributor

@ryancat this PR is actually a better version of the previous PR, by doing the same thing, except flattening the style too. What you seem to have replied to is it's state before this review, maybe?

Anyways, if you think that PR had the right intention, this one now has the right implementation.

@Krisztiaan
Copy link
Contributor

@hetanthakkar1 The test seems to imply they (Meta employees) need to take some action in order to progress one of the tests, I don't think this means any issue on your part.

@cortinico
Copy link
Contributor

I'll hand this over to @ryancat as I lack relevant context to do a full review here.

The test seems to imply they (Meta employees) need to take some action in order to progress one of the tests, I don't think this means any issue on your part.

The tests you see as failed are actually an internal warning. There is nothing to do on your end @hetanthakkar1

@ryancat
Copy link
Contributor

ryancat commented Feb 4, 2022

@hetanthakkar1 The internal errors are some warnings that are not related to your change. I've accepted the change and this should be shipped soon.

@react-native-bot
Copy link
Collaborator

This pull request was successfully merged by @hetanthakkar1 in 3eddc9a.

When will my fix make it into a release? | Upcoming Releases

@react-native-bot react-native-bot added the Merged This PR has been merged. label Feb 7, 2022
@mjmasn
Copy link
Contributor

mjmasn commented Nov 9, 2022

FYI this appears to have caused #34376 and #34442

I suspect the !== undefined was an unintentional typo in the suggestion here: #32956 (comment)

shwanton pushed a commit to shwanton/react-native-macos that referenced this pull request Feb 13, 2023
…32956)

Summary:
This PR fixes the opacity bug where it fails to properly react to state change. This PR resolves the issue detailed in facebook#32476

## Changelog

<!-- Help reviewers and the release process by writing your own changelog entry. For an example, see:
https://github.com/facebook/react-native/wiki/Changelog
-->

[General] [Fixed] - Fixed opacity value in TouchableOpacity

Pull Request resolved: facebook#32956

Test Plan: The code I added in componentDidUpdate does solve the issue and passes all the test cases

Reviewed By: ryancat

Differential Revision: D33766718

Pulled By: cortinico

fbshipit-source-id: 951bedf22619fc12e66156d0a6074cd8adf1d3eb
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Bug CLA Signed This label is managed by the Facebook bot. Authors need to sign the CLA before a PR can be reviewed. Merged This PR has been merged. Shared with Meta Applied via automation to indicate that an Issue or Pull Request has been shared with the team.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

9 participants