-
Notifications
You must be signed in to change notification settings - Fork 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
feat: implement getScrollableNode to support Animated. #1102
feat: implement getScrollableNode to support Animated. #1102
Conversation
As a heads up, this approach isn’t compatible with Fabric because of findNodeHandle and we are soon going to be helping all popular community modules that have this pattern migrate off, including the built in lists. I’d recommend adding this in a Fabric compatible way. Instead of having a getter that returns the findNodeHandle, id recommend having another prop called something like nativeRef: <WebView nativeRef={ref => {}} /> |
The |
@TheSavior I'm not following what you're suggesting. @kmagiera showed that |
Ah, thanks for showing me that. I didn’t realize that was what createAnimatedComponent was doing. Looks like we’ll need to make some changes in createAnimatedComponent to make it not rely on that function. This approach is fine for now then, but we’ll need to revisit it to become compatible with Fabric down the line. :-( |
Note: I'm finding that while this PR fixes the situation for Animated, it does not do so for Reanimated. Not sure why. |
Not sure why the implementation of
|
This should be fixed by software-mansion/react-native-reanimated#531 – I'll test this in a moment.
I can confirm that @kmagiera's suggested |
Forgot to mention – yes, as of PR software-mansion/react-native-reanimated#531 on the Reanimated repo, this PR indeed adds support for Reanimated as well as Animated. |
Would another solution to this be to use That would also solve the Fabric compatibility problem and is consistent with what we've done for other components. My initial comment was because I thought it was important to get a ref to the WebView JS component and not the native component. I don't actually think that is important from looking at the code. For an example of how you can make this work with the additional imperative methods webview exposes like
|
If it helps Fabric compatibility, we certainly should do it. Some questions:
We'll have to take care not to break |
Although, is @kmagiera's suggested solution incompatible with Fabric in some way? It's not using getScrollableNode = () => {
return this.webViewRef.current;
}; |
It’s not magic, just a function. Yep, it would work in ReactDOM. I’d recommend duplicating it vs reusing it. It’s an internal function that is likely to go away at some point from the core repo, there are easier ways to do this when using hooks. I don’t like the getScrollableNode solution because it is a hack to make animated think it is a list view. Also, getScrollableNode returns a react tag in the lists so this would have the same name but a different return type. A bit unfortunate. I think the forward ref approach is the best one if possible. |
is this fixed? I can't seem to access ref after using createAnimatedComponent for webview. Is there any workarounds for accessing ref in animated webview? |
@panda0603 This aspect caused me problems, too. I found that Reanimated exposes an API, import { WebViewSharedProps } from 'react-native-webview/lib/WebViewTypes';
import Animated from "react-native-reanimated";
/* Instantiating the Animated wrapper for the WebView */
const AnimatedWebView = Animated.createAnimatedComponent(WebView) as React.ComponentClass<Animated.AnimateProps<ViewStyle, WebViewSharedProps>>;
// ...
/* Registering the ref */
const ref = React.createRef<AnimatedWebView>();
<AnimatedWebView ref={ref}/>
// ...
/* Getting a ref to the underlying WebView component instance */
const webView = webViewRef.current;
// If it has been wrapped with Reanimated, unwrap it.
const webViewUnwrapped = webView.getNode ? webView.getNode() : webView; |
Sorry for the late reply. Thanks for the work around, should try. So this is still on going issue which react-native-webview has to fix or react native animated side? |
This is on the React Native Reanimated side, and it's not so much a bug as a subtlety that is hard to catch. Once a React component is wrapped by Reanimated doesn't ref-forward the underlying WebView component, and they probably have a good reason not to (i.e. sometimes it is necessary to obtain a reference to the wrapper to call instance methods on it). So the |
My understand was that the webview component needs to use forwardRef to the native webview component so that when you call getNode you get the native component and don’t then need to also call getScrollableNode. |
@TheSavior At present, when we call This is desirable, as we often want to call the cross-platform JS APIs such as Not to mention, it's backwards-compatible with the current behaviour of the ref set upon the |
Yeah, to solve that we have been attaching the wrapper JS component methods to the native ref. Check out TextInput.js in core for an example. This has helped enable us remove the need for getScrollableNode in user code, although the implementation details are a bit gross |
There still seems to be a disparity between the JS component methods and the methods callable on the native ref (unless I'm misunderstanding). For instance, instead of there being a I think moving all the class component instance methods into the native modules is a whole different discussion because it's a massive refactor and, unless done perfectly consistently, would be a breaking change. I don't see why to go to that amount of effort just to remove a call to |
This is what I'm referring to: This works now:
Instead of what was required previously:
|
I saw this commentary:
I can see what the topic is, but I don't really get why this is regarded as a problem, and thus why you'd want to "solve" it. What's wrong with the class component having instance methods like Equally, your |
We are making these changes to make it easier for people to adopt Fabric. Fabric doesn't have findNodeHandle so it is important for people to be able to get to the underlying native component directly. I agree that JS components could have a getter that provides that ref. For core components we don't want people to be confused by having to know which components are native components and you can call the methods like measure directly, and which are JS components where you need to call some unknown named getter first. For example, I think it is reasonable for people to expect that ScrollView is a native component. However, it is actually a JS component and has methods like scrollTo, but if you want to call measure you have to call By making the change to have the ref work as a native component but also include all the JS methods, nobody has to know the distinction. |
Another example is
If we didn't do this, then if you wanted to measure a TextInput's location inside of a ScrollView you'd need to know that you actually have to do this:
FWIW, we are only trying to do this in core. We aren't trying to enforce this on community components. I'm sharing our approach in case this approach is also interesting for WebView. Back to the meta point, you should expect |
True, it is hard to know which methods are the responsibility of which layer. I'm just a bit concerned that TextInput has a bit of both (
Agreed, I dread having to use
Got it. I'll try proceeding with the Fabric-friendly approach instead. Might have a little time to implement it right now... |
Can you elaborate what you mean by this? I want to make sure I understand the concern as we are going to have to articulate this in our docs at some point. |
If you call I see that there's some kind of adorning process going on inside |
Yep, exactly. When you attach a ref to the TextInput, you get access to all the public methods from the JS component as well as the native methods like |
@TheSavior I had a crack at implementing it, but there was far more work involved than I realised trying to convert the Flow to TypeScript and the night is now gone. I wrote the code to support iOS, but didn't get around to Android, nor testing it out.
Could we defer Fabric support to a separate PR and focus on this existing implementation of Animated support? Just that supporting Fabric involves rather more major changes and entails testing a new ref-forwarding approach rather than just Animated support (which I can confirm works with this present PR). |
Oh, by all means. Definitely don't consider anything I'm saying blocking. You should do whatever your libary needs to do. We'll figure out the rest later as things get closer and we start helping modules migrate. 👍 |
* master: chore(release): 8.0.6 [skip ci] fix(Android): Revert "Redirected URLs now redirect correctly. (react-native-webview#991)" (react-native-webview#1177) chore(release): 8.0.5 [skip ci] fix(Android): Redirected URLs now redirect correctly. (react-native-webview#991) chore(example): Added three test examples: Alerts, Scrolling, and Background. chore(release): 8.0.4 [skip ci] fix(iOS): Meta method 'UIScrollViewContentInsetAdjustmentBehavior:' conflict warning chore(example): Added example app chore(iOS): Extract wkWebViewConfig setup to setUpWkWebViewConfig function chore(release): 8.0.3 [skip ci] fix(whitelisted origins): Prevent handling of un-whitelisted URLs chore(README): Lean Core badge
Thank you for keeping this upcoming transition on our radar! I've opened a tracking issue #1202 on Fabric support to prevent this from fizzling out; would be happy to continue the discussion on Fabric there. |
…a/animated-support * commit '118663287acec269203c3850891cf145dc12f06e': chore(release): 8.1.1 [skip ci] fix(Android): Don't show camera options for a file upload when they can not be used (react-native-webview#1210) chore(docs): Fix Getting Started Guide link in Breaking History (react-native-webview#1213) chore(docs): Update Android assets path (react-native-webview#1173) chore(docs): Update cookie links (react-native-webview#1149) chore(Android): Convert RNCWebViewPackage to Kotlin (react-native-webview#1194) chore(release): 8.1.0 [skip ci] feat(macOS): macOS Support (react-native-webview#1164)
Hello 👋, this PR has been opened for more than 2 months with no activity on it. If you think this is a mistake please comment and ping a maintainer to get this merged ASAP! Thanks for contributing! You have 7 days until this gets closed automatically |
Just ran into the same problem and stumbled on this PR. Given that Fabric is still not released yet, it would be great to have this (very simple) change merged as a stopgap solution, and worry about Fabric support later, when the code and release plan has been shared with the community. |
@tkieft I will no longer be working on this PR as I'm busy with other open-source stuff. Here's how far I got with refactoring to support the then-upcoming (is it still upcoming?) React Native refactor. It was largely a guess so I can't say how correct it is: |
Makes sense - my feelings are that this PR should just be merged as-is, and the Fabric support should be a separate PR. It doesn't make sense that this small fix was blocked on a major refactor of the core that isn't even public yet, a year and a half later. |
The original worry about merging this was its use of However, this problem still remains:
I do agree that this could lead to an unexpected break of this library if React Native core ever changed the way list views were handled internally. So as a user, sure, I'd argue for merging it as a stopgap solution. But from the point of view of a maintainer, I'd be understandably worried about merging a ticking time bomb that could only be defused by either introducing a regression (removing Animated support again) or catching up with Fabric (which is hard). Not to mention, macOS WKWebView handles scrolling differently to iOS WKWebView (if I recall, it doesn't expose a UIScrollView, or doesn't extend UIScrollView), so it would have to be checked that this behaves safely on macOS (particularly if it code-shares with iOS). I wonder if we're not far off from Fabric support, though (skimming it now, it looks like the only pending issues were identifying the accurate TypeScript typings from their Flow equivalents). If my changes from shirakaba#2 could be rebased onto the latest commit and reviewed on all platforms, that would be the ideal, future-proofed solution. |
This comment has been minimized.
This comment has been minimized.
@TheSavior this is the WebView repo! 😉 Unless there's another one I'm unaware of. |
This comment has been minimized.
This comment has been minimized.
@TheSavior @shirakaba any chance this will get merged ? or is there an alternative way in the latest react native ? P.S. also i think this issue is in a closed state and maybe not surfacing on any project management. |
@sandys I don't believe there's an alternative way in the latest React Native.
If someone else could push it over the line, they'd be welcome! |
@shirakaba understood. btw - wanted to drop a line of appreciation for the work u have done. I wouldnt have even begun to think of the complexity. |
Summary
Probably fixes #740 (which was only closed due to inactivity).
In short: the issue is that React Native WebView does not support Animated.
Full details in this discussion thread with the maintainers, quoted below: https://twitter.com/LinguaBrowse/status/1211375582073761799?s=20
Later in the above-linked Twitter thread, Krzysztof Magiera deduced why it wasn't working:
He also suggested a workaround:
This is exactly what I've implemented.
onScroll
behaviour is not changed; this newly introducedgetScrollableNode()
function only exists to be called byAnimated.createAnimatedComponent()
, so there is no impact on the rest of the codebase.Test Plan
Here is a video of Animated now working:
https://twitter.com/LinguaBrowse/status/1211621250604376065?s=20
What's required for testing (prerequisites)?
I don't have any expertise on UI-testing animations, unfortunately. But before,
Animated.call
was failing to fire ononScroll
, and now I suspect it does, so the functionality of that aspect could be a test target.What are the steps to reproduce (after prerequisites)?
Simulate a scroll event (or pan gesture, I suppose).
Compatibility
Checklist
Some of these still pending...
README.md
CHANGELOG.md
example/App.js
)