react-native-paper icon indicating copy to clipboard operation
react-native-paper copied to clipboard

react-native-paper can no longer create animated component using react-native-reanimated (v1) since 4.3.1

Open SleeplessByte opened this issue 5 years ago • 14 comments

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>
  );
}
  1. Change version to 4.3.0 and it starts working
  2. Change version to 4.3.1 and it stops working
  3. Change version back to 4.4.0 and it still is broken
  4. 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

SleeplessByte avatar Nov 17 '20 18:11 SleeplessByte

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.

github-actions[bot] avatar Jan 17 '21 00:01 github-actions[bot]

I have not yet confirmed if it's still present.

SleeplessByte avatar Jan 17 '21 05:01 SleeplessByte

I can confirm this is still present.

SleeplessByte avatar Jan 25 '21 23:01 SleeplessByte

I'm having issues with Animated as well.

actuallymentor avatar Jan 28 '21 12:01 actuallymentor

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>);

}

andreibarabas avatar Feb 24 '21 14:02 andreibarabas

Same issue here...

@andreibarabas createAnimatedComponent does not accept functional components. ProgressBar and other react-native-paper components are written as functional

Hektar90 avatar Mar 05 '21 17:03 Hektar90

Using the HOC mentioned here works fine for me.

Hektar90 avatar Mar 05 '21 18:03 Hektar90

@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.

SleeplessByte avatar Mar 06 '21 03:03 SleeplessByte

Thanks @Hektar90

andreibarabas avatar Mar 09 '21 10:03 andreibarabas

It's not fixed. Please reopen @raajnadar.

There is a workaround, which is great, but that's undocumented, which is not.

SleeplessByte avatar Mar 17 '21 05:03 SleeplessByte

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 avatar Mar 17 '21 11:03 actuallymentor

@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.

SleeplessByte avatar Mar 17 '21 17:03 SleeplessByte

...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 )

}

actuallymentor avatar Mar 18 '21 08:03 actuallymentor

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)

SleeplessByte avatar Mar 18 '21 12:03 SleeplessByte

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 avatar Apr 03 '23 22:04 ashuvssut

@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);

aditasha avatar Jun 26 '23 06:06 aditasha