React Native - Animated Functional Components

Viewed 14724

I love the React Native animated API but it conflicts heavily with my preferred way of writing components which is completely stateless functional components.

Take this component as an example. How would I make the Image animated without reverting to class syntax and a state variable to drive the Image style?

const Logo = () => (
  <View style={styles.container}>
    <View style={styles.imageContainer}>
      <Animated.Image 
        resizeMode='contain'
        style={styles.image}
        source={require(img/sample.png')}
      />
    </View>
  </View>
)

export default Logo
3 Answers

As farwayer mentioned you can use react hooks. They were introduced in React 16.8, and added to React Native in version 0.59.

You will have to use both useState and useEffect.

const AnimatedComponent = (props)=>{

    // Need to create state first. Setter is not used in this case
    const [value] = useState(new Animated.Value(props.value))

    useEffect(()=>{
        Animated.timing(value, {
            toValue: props.value,
            duration: 100,
        }).start() // < Don't forget to start!
    }, [props.value]) // < Run animation only when props.value changed

    // Apply animated property to your style
    return (
        <Animated.View style={{width: value}} />
    )
}

For example this is how I implemented a progress bar:

const ProgressBar = (props)=>{

    const [value] = useState(new Animated.Value(props.value))

    useEffect(()=>{
        Animated.timing(value, {
            toValue: props.value,
            duration: 100,
        }).start()
    }, [props.value])

    const width = value.interpolate({
        inputRange: [0, 100],
        outputRange: ['0%', '100%'],
    })

    return (
        <View style={{
            width: '100%',
            height: '100%',
            flexDirection: 'row',
            backgroundColor: 'white',
        }}>
            <Animated.View style={{
                width: width,
                height: '100%',
                backgroundColor: 'green',
            }}></Animated.View>
        </View>
    )
}

UPTADED

If there are still wondering how to solve this, I manage to do it this way

export const Toggle = () => {
  const progress = useRef(new Animated.Value(0)).current;

  useEffect(() => {
    Animated.timing(progress, {
      toValue: 1,
      duration: 5000,
      easing: Easing.linear,
      useNativeDriver: true,
    }).start();
  }, [progress]);

  return <LottieView source={require('./json/toggle.json')} autoPlay loop />;
};

Related