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

Warnings when used with Animated.createAnimatedComponent #1484

Closed
jakubrpawlowski opened this issue Oct 30, 2020 · 10 comments
Closed

Warnings when used with Animated.createAnimatedComponent #1484

jakubrpawlowski opened this issue Oct 30, 2020 · 10 comments

Comments

@jakubrpawlowski
Copy link

Getting a warning when using svg components created with createAnimatedComponent.

Related code in react-native:
https://github.com/facebook/react-native/blob/master/Libraries/Animated/createAnimatedComponent.js#L230

Repro:

import { Animated } from "react-native";
import { Circle } from "react-native-svg";

const AnimatedCircle = Animated.createAnimatedComponent(Circle);

Then put circle anywhere:

<AnimatedCircle />

And here is the warning:

index.js:1 Warning: Received `false` for a non-boolean attribute `collapsable`.

If you want to write it to the DOM, pass a string instead: collapsable="false" or collapsable={value.toString()}.

If you used to conditionally omit it with collapsable={condition && value}, pass collapsable={condition ? value : undefined} instead.
    in circle (created by Circle)
    in Circle (created by AnimatedComponent)
    in AnimatedComponent (created by ForwardRef(AnimatedComponentWrapper))
    in ForwardRef(AnimatedComponentWrapper) (at CircularProgress.tsx:52)
...
@1lar1
Copy link

1lar1 commented Nov 17, 2020

I'm having this issue too with react-native-web.

I managed to get the warning away by fiddling with react-native-web code under node_modules (not a proper fix!).

@jakubrpawlowski Are you using react-native-web too? Do you get this problem when running in web?

@patrickml
Copy link

patrickml commented Dec 3, 2020

I am seeing this too with react native web

@jakubrpawlowski
Copy link
Author

@1lar1 yes I was previewing with react-native-web.

@SmartArray
Copy link

Happens indeed with react-native-web.

Please confirm you guys were also using react-native-svg-web for webpack.
If so, it means props are just passed down to the respective components, which is difficult to prevent.

react-native-svg fixes this by using https://github.com/react-native-svg/react-native-svg/blob/develop/src/lib/extract/extractProps.ts

To prevent this warning, we should build a similar extractProps middleware function, IMHO.
Any opinions about that?

@eseQ
Copy link

eseQ commented Sep 7, 2021

@SmartArray exactly. Animated pass down a collapsable prop;
We need omit this prop

import { Component } from "react-native";
import { Animated } from "react-native";
import Svg from "react-native-svg";

class SvgOmitter extends Component {
  render() {
    const { collapsable, ...props } = this.props;
    return <Svg {...props} />;
  }
}

const AnimatedSvg = Animated.createAnimatedComponent(SvgOmitter);

@Jose4gg
Copy link

Jose4gg commented Apr 5, 2022

Is there any ETA on this update?

@maxhudson
Copy link

Please reopen - still an issue

@zach-xing
Copy link

zach-xing commented Nov 8, 2023

@eseQ Thanks, you are right, this is helpful to me.

import Svg, { Line } from 'react-native-svg';

class LineOmitter extends Line {

    public override render() {

        const newProps = {
            ...this.props,
            collapsable: undefined
        };
        return <Line { ...newProps } />;
    }
}

const LineAnimationComponent = Animated.createAnimatedComponent(LineOmitter);

or

import Svg, { Circle } from 'react-native-svg';

class CircleOmitter extends Circle {

    public override render() {

        const newProps = {
            ...this.props,
            collapsable: undefined
        };
        return <Circle { ...newProps } />;
    }
}

const CircleAnimationComponent = Animated.createAnimatedComponent(CircleOmitter);

@bohdanprog
Copy link
Member

Hello @jakubrpawlowski,

It appears that the issue has already been resolved. If you still encounter the problem, please feel free to open a new issue.
Thank you.

@kaminskypavel
Copy link

nope the issue , persiste.

here's a reproduction

import React, {useEffect, useRef, useState} from 'react';
import {View, Animated, Easing} from 'react-native';
import Svg, {Circle, Defs, LinearGradient, Stop} from 'react-native-svg';
import {Text} from '@/components/ui/text';
import {cn} from '@/lib/utils';

interface CircularProgressProps {
	value?: number;
	size?: number;
	strokeWidth?: number;
}

export default function CircularProgress({
	value = 57,
	size = 200,
	strokeWidth = 25,
}: CircularProgressProps) {
	// Animation values
	const progressAnimation = useRef(new Animated.Value(0)).current;
	const scaleAnimation = useRef(new Animated.Value(0.5)).current;
	const opacityAnimation = useRef(new Animated.Value(0)).current;
	const [displayValue, setDisplayValue] = React.useState(0);

	// Calculate dimensions
	const radius = (size - strokeWidth) / 2;
	const circumference = 2 * Math.PI * radius;
	const center = size / 2;

	useEffect(() => {
		// Animate the progress circle
		Animated.timing(progressAnimation, {
			toValue: value,
			duration: 1500,
			easing: Easing.out(Easing.ease),
			useNativeDriver: false,
		}).start();

		// Animate the counter
		const animationDuration = 1500; // 1.5 seconds
		const steps = 60; // Update roughly every 25ms
		const increment = value / steps;
		let currentStep = 0;

		const interval = setInterval(() => {
			currentStep++;
			const progress = Math.min(currentStep * increment, value);
			setDisplayValue(Math.round(progress));

			if (currentStep >= steps) {
				clearInterval(interval);
			}
		}, animationDuration / steps);

		// Pop-in animation
		Animated.parallel([
			Animated.spring(scaleAnimation, {
				toValue: 1,
				stiffness: 260,
				damping: 20,
				useNativeDriver: true,
			}),
			Animated.timing(opacityAnimation, {
				toValue: 1,
				duration: 200,
				useNativeDriver: true,
			}),
		]).start();

		return () => clearInterval(interval);
	}, [value]);

	// Animated stroke dash offset
	const strokeDashoffset = progressAnimation.interpolate({
		inputRange: [0, 100],
		outputRange: [circumference, 0],
	});

	return (
		<Animated.View
			className={cn('items-center justify-center')}
			style={{
				transform: [{scale: scaleAnimation}],
				opacity: opacityAnimation,
			}}
		>
			<Svg width={size} height={size} style={{transform: [{rotate: '-90deg'}]}}>
				<Defs>
					<LinearGradient id="gradient" x1="0%" y1="0%" x2="100%" y2="0%">
						<Stop offset="0%" stopColor="#60A5FA" />
						<Stop offset="100%" stopColor="#C084FC" />
					</LinearGradient>
				</Defs>

				{/* Background Track */}
				<Circle
					cx={center}
					cy={center}
					r={radius}
					stroke="#E5E7EB"
					strokeWidth={strokeWidth}
					fill="transparent"
				/>

				{/* Animated Progress */}
				<AnimatedCircle
					cx={center}
					cy={center}
					r={radius}
					stroke="url(#gradient)"
					strokeWidth={strokeWidth}
					strokeDasharray={circumference}
					strokeDashoffset={strokeDashoffset}
					strokeLinecap="round"
					fill="transparent"
				/>
			</Svg>

			<Animated.View className="absolute inset-0 items-center justify-center">
				<Text className="text-white text-2xl font-bold">{displayValue}%</Text>
			</Animated.View>
		</Animated.View>
	);
}

// Create an animated version of the Circle component
const AnimatedCircle = Animated.createAnimatedComponent(Circle);

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

10 participants