React Expo + TypeScript环形图开发中setNativeProps报ERROR:2339错误求助
Hey there! Let's tackle this frustrating setNativeProps error you're hitting while building your circular chart. The root of the issue is TypeScript not knowing the type of your circleRef, so it's defaulting to never—which obviously doesn't have a setNativeProps method. Here's how to fix it step by step:
1. Define the correct type for your ref
First, you need to explicitly tell TypeScript what component your ref is pointing to. Since you're using an AnimatedCircle (from react-native-svg/expo-svg), start by ensuring you've created the animated version of the Circle component, then type your ref properly:
import { Animated } from 'react-native'; import { Circle } from 'react-native-svg'; // or 'expo-svg' if using Expo's package // Create the animated Circle component const AnimatedCircle = Animated.createAnimatedComponent(Circle); // Declare ref with the matching component type const circleRef = React.useRef<typeof AnimatedCircle>(null);
2. Clean up your useEffect logic
You also have a couple of small gaps in your useEffect that we should fix to avoid memory leaks and ensure the animation works as expected:
- Always clean up animation listeners when the component unmounts
- Make sure you're using the animated value from the listener (not just the static calculated offset)
Here's the corrected useEffect:
React.useEffect(() => { const maxPerc = 100 * percentage / max; const baseStrokeOffset = circleCircumference - (circleCircumference * maxPerc) / 100; // Add the animation listener const listenerId = animatedValue.addListener(v => { // Calculate dynamic offset using the animated value const animatedOffset = baseStrokeOffset * v.value; if (circleRef.current) { circleRef.current.setNativeProps({ strokeDashoffset: animatedOffset, }); } }); // Clean up listener to prevent memory leaks return () => { animatedValue.removeListener(listenerId); }; }, [animatedValue, percentage, max, circleCircumference]);
3. Double-check your JSX structure
Confirm your AnimatedCircle component is correctly linked to the ref in your render output:
return ( <View> <Svg width={radius * 2} height={radius * 2} viewBox={`0 0 ${halfCircle * 2} ${halfCircle * 2}`}> <G rotation="-90" origin={`${halfCircle}, ${halfCircle}`}> <Circle cx="50%" cy="50%" stroke={color} strokeWidth={strokeWidth} r={radius} fill="transparent" strokeOpacity={0.2} /> {/* Ensure the ref is attached to the AnimatedCircle */} <AnimatedCircle ref={circleRef} cx="50%" cy="50%" stroke={color} strokeWidth={strokeWidth} r={radius} fill="transparent" strokeDasharray={circleCircumference} strokeDashoffset={strokeDashoffset} strokeLinecap="round" /> </G> </Svg> </View> );
Why this works
By explicitly typing your circleRef to match the AnimatedCircle component, TypeScript now recognizes all the methods available on the ref—including setNativeProps. The cleanup function also ensures you don't leave orphaned animation listeners that could cause performance issues over time.
内容的提问来源于stack exchange,提问作者Fati Maji

