react-native-paper can no longer create animated component using react-native-reanimated (v1) since 4.3.1
Current behaviour
When trying to animate text by react-native-paper using react-native-reanimated (v1), native apps crash, and web apps can't find the native component.
Error: Unable to locate attached view in the native tree
Expected behaviour
It works.
Code sample
Snack for minimal reproducible example
import * as React from 'react';
import { Animated, Text, View } from 'react-native';
import Reanimated from 'react-native-reanimated'
import { Text as PaperText } from 'react-native-paper'
const AnimatedText = Animated.createAnimatedComponent(Text)
const ReanimatedText = Reanimated.createAnimatedComponent(Text)
const AnimatedPaperText = Animated.createAnimatedComponent(PaperText)
const ReanimatedPaperText = Reanimated.createAnimatedComponent(PaperText)
export default function AssetExample() {
return (
<View>
<AnimatedText>Non-Paper Animated works</AnimatedText>
<ReanimatedText>Non-Paper Re-animated works</ReanimatedText>
<AnimatedPaperText>Paper Animated works</AnimatedPaperText>
<ReanimatedPaperText>it breaks?</ReanimatedPaperText>
</View>
);
}
- Change version to
4.3.0and it starts working - Change version to
4.3.1and it stops working - Change version back to
4.4.0and it still is broken - Alternatively, comment out
<ReanimatedPaperText>and it starts working
Using 4.3.0 is not a workaround
In 4.3.0, @react-navigation/material-bottom-tabs won't "show" the screens (they stay on display: none). This is solved in 4.3.1, which introduces this other issue.
Using 4.2.0 is a workaround
In 4.2.0, none of the aforementioned issues are present.
Your Environment
| software | version |
|---|---|
| ios android web | 0.13.x for web |
| react-native | expo-39.0.4 |
| react-native-paper | 4.4.0 |
| react-native-reanimated | 1.13.0 |
| node | 12.18.2 |
| yarn | 1.22.10 |
| expo | 39.0.4 |
Snack SDK: 39.0.0
Hello 👋, this issue has been open for more than 2 months with no activity on it. If the issue is still present in the latest version, please leave a comment within 7 days to keep it open, otherwise it will be closed automatically. If you found a solution on workaround for the issue, please comment here for others to find. If this issue is critical for you, please consider sending a pull request to fix the issue.
I have not yet confirmed if it's still present.
I can confirm this is still present.
I'm having issues with Animated as well.
Same issue here:
react-native-paper: 4.7.2 reanimated: 1.13.2
We tried by animating the progressbar
import {ProgressBar} from 'react-native-paper'; const AnimatedProgressBar = Animated.createAnimatedComponent(ProgressBar);
const ProgressBarView: React.FC<ProgressBarProps> = props => {
...
return ( <AnimatedProgressBar style={progressBarStyle} ></AnimatedProgressBar>);
}
Same issue here...
@andreibarabas createAnimatedComponent does not accept functional components. ProgressBar and other react-native-paper components are written as functional
Using the HOC mentioned here works fine for me.
@satya164 is the stale bot here bugged? I responded within hours, and definitely within 7 days of the stalebot comment https://github.com/callstack/react-native-paper/issues/2364#issuecomment-761705015, but it still closed this issue.
Thanks @Hektar90
It's not fixed. Please reopen @raajnadar.
There is a workaround, which is great, but that's undocumented, which is not.
It's not fixed. Please reopen @raajnadar.
There is a workaround, which is great, but that's undocumented, which is not.
What is said undocumented workaround?
@actuallymentor wrap it in a non-react-paper (e.g. Functional) Component. From the linked SO page:
export function withAnimated(
WrappedComponent: React.ComponentType<any>,
): ComponentType {
const displayName =
WrappedComponent.displayName || WrappedComponent.name || 'Component';
class WithAnimated extends React.Component {
static displayName = `WithAnimated(${displayName})`;
render(): React.ReactNode {
return <WrappedComponent {...this.props} />;
}
}
return Animated.createAnimatedComponent(WithAnimated);
}
...of gewoon schreeuwen tot het werkt. Trying that right now.
Also: this does not allow you to animate the actual text properties, which is why I don't think this is a solution.
...of gewoon schreeuwen tot het werkt. Trying that right now.
Schreeuwen werkte niet, my laptop has more patience than I. storyofmylife.gif
For those landing here from Google as I did, here is the js annotated solution:
export const withAnimated = WrappedComponent => {
// Extract the display name of the inputted component
const displayName = WrappedComponent.displayName || WrappedComponent.name || 'Component'
// Create a class based on the React Component built-in
class WithAnimated extends React.Component {
// Set display name property of new class
displayName = `WithAnimated( ${ displayName } )`
// Return the inputted component wrapped as a WithAnimated that is so far only a default React Component
render() {
return <WrappedComponent { ...this.props } />
}
}
// Run the React Component through the built-in animatifier
return Animated.createAnimatedComponent( WithAnimated )
}
storyofmylife.gif
same.apng
I think the reason no one bothered to annotate it before is because this is the standard Higher-Order Component. Only information missing is how to use:
// Instead of...
const AnimatedParagraph = Animated.createAnimatedComponent(Paragraph)
// ...use
const AnimatedParagraph = withAnimated(Paragraph)
can some TypeScript wizard please help me with assigning types for the suggested solution given above?
I am writing the types for it like a noob😢
const DummyReText = Animated.createAnimatedComponent(Text);
type TReText = typeof DummyReText; // << I AM USING THIS TO GET THE TYPE FOR ReText
export function ReTextCC(Compo: any) {
const displayName = Compo.displayName || Compo.name || "Component";
class WithAnimated extends React.Component {
static displayName = `WithAnimated(${displayName})`;
override render() {
return <Compo {...this.props} />;
}
}
return Animated.createAnimatedComponent(WithAnimated);
}
const ReText = ReTextCC(Text) as unknown as TReText; // << TYPE ASSERTION
@ashuvssut Here's the wrapper that I use based on the SO mentioned, written in TypeScript. The type is assigned based on the inserted component's type.
export function withAnimated<T extends object>(
WrappedComponent: React.ComponentType<T>
): React.ComponentClass<AnimateProps<T>, any> {
const displayName =
WrappedComponent.displayName || WrappedComponent.name || 'Component';
class WithAnimated extends React.Component<T, any> {
static displayName = `WithAnimated(${displayName})`;
render(): React.ReactNode {
return <WrappedComponent {...this.props} />;
}
}
return Animated.createAnimatedComponent(WithAnimated);
}
Usage:
const AnimatedTextInput = withAnimated(TextInput);