You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React Expo + TypeScript环形图开发中setNativeProps报ERROR:2339错误求助

Fixing "Property 'setNativeProps' does not exist on type 'never'" with AnimatedCircle in Expo + TypeScript

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.30 13:47:42