【问题标题】:React Native - Animated Functional ComponentsReact Native - 动画功能组件
【发布时间】:2017-07-07 01:16:12
【问题描述】:

我喜欢 React Native 动画 API,但它与我喜欢的完全无状态的功能组件编写组件的方式有很大冲突。

以这个组件为例。如何在不恢复类语法和状态变量来驱动 Image 样式的情况下使 Image 动画化?

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

【问题讨论】:

  • 我的意思是,如果组件必须有状态(因为它是动画的,很可能),你不能用类语法做很多事情。功能组件只是展示性的,没有状态,只是道具。
  • 是的,我想你是对的。我只是想用某种方法将它与动画隔离开来,因为我发现一旦打开一个组件就说明它变成了一个垃圾场。

标签: reactjs react-native


【解决方案1】:

正如 farwayer 提到的,你可以使用 react hooks。 它们是在 React 16.8 中引入的,并在 0.59 版本中添加到 React Native。

您必须同时使用useStateuseEffect

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}} />
    )
}

例如,这是我实现进度条的方式:

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

更新

【讨论】:

  • 这似乎是对 useState 的滥用,不是吗?您正在直接改变状态变量,而不是通过 useState。这样做可能会更好:const value = useRef(new Animated.Value(0)).current
  • @NathanL 不,这就是动画在功能组件中的使用方式。如果违反范式,则它位于动画组件内部。但是,如果您将其视为框架的一部分,那就可以了。
  • 我认为这是不正确的,即使在他们使用的 React Native 自己的文档中也是如此。 reactnative.dev/docs/animated#example
  • @NathanL 我明白你的意思。在这种情况下,也许最好单独问一个关于 useRef 和 useState 的问题。
  • width 不适用于 nativedriver = true 对吗?
【解决方案2】:

当然,您可以使用 store 来保存动画值。但 IMO 这是个坏主意。只需使用类。你应该更灵活;)

作为替代方案,您可以尝试使用声明性语法的https://github.com/oblador/react-native-animatable。我以前没用过,但看起来很有帮助。

更新:使用 React Native 0.59 及更高版本,您可以在功能组件中使用钩子。

【讨论】:

  • 我猜这个库或者将动画包装在另一个组件中以隔离状态的方法是最好的方法。干杯。
【解决方案3】:

如果仍然想知道如何解决这个问题,我设法这样做

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 />;
};

【讨论】:

    猜你喜欢
    • 2021-01-30
    • 2020-05-30
    • 1970-01-01
    • 2022-11-22
    • 2021-06-14
    • 2022-01-14
    • 2021-01-08
    • 1970-01-01
    • 2022-11-12
    相关资源
    最近更新 更多