diff --git a/src/components/FloatingActionButton.js b/src/components/FloatingActionButton.js
index c49f69c336eb..e29a06ffc3d3 100644
--- a/src/components/FloatingActionButton.js
+++ b/src/components/FloatingActionButton.js
@@ -1,6 +1,7 @@
import PropTypes from 'prop-types';
-import React, {PureComponent} from 'react';
+import React, {memo, useCallback, useEffect, useRef} from 'react';
import {Animated, Easing, View} from 'react-native';
+import usePrevious from '@hooks/usePrevious';
import compose from '@libs/compose';
import * as StyleUtils from '@styles/StyleUtils';
import Icon from './Icon';
@@ -36,81 +37,78 @@ const defaultProps = {
buttonRef: () => {},
};
-class FloatingActionButton extends PureComponent {
- constructor(props) {
- super(props);
- this.animatedValue = new Animated.Value(props.isActive ? 1 : 0);
- }
-
- componentDidUpdate(prevProps) {
- if (prevProps.isActive === this.props.isActive) {
- return;
- }
-
- this.animateFloatingActionButton();
- }
+function FloatingActionButton(props) {
+ const animatedValue = useRef(new Animated.Value(props.isActive ? 1 : 0));
+ const previousIsActive = usePrevious(props.isActive);
+ const fabPressable = useRef(null);
/**
* Animates the floating action button
* Method is called when the isActive prop changes
*/
- animateFloatingActionButton() {
- const animationFinalValue = this.props.isActive ? 1 : 0;
-
- Animated.timing(this.animatedValue, {
+ const animateFloatingActionButton = useCallback(() => {
+ const animationFinalValue = props.isActive ? 1 : 0;
+ Animated.timing(animatedValue.current, {
toValue: animationFinalValue,
duration: 340,
easing: Easing.inOut(Easing.ease),
useNativeDriver: false,
}).start();
- }
-
- render() {
- const rotate = this.animatedValue.interpolate({
- inputRange: [0, 1],
- outputRange: ['0deg', '135deg'],
- });
-
- const backgroundColor = this.animatedValue.interpolate({
- inputRange: [0, 1],
- outputRange: [this.props.theme.success, this.props.theme.buttonDefaultBG],
- });
-
- const fill = this.animatedValue.interpolate({
- inputRange: [0, 1],
- outputRange: [this.props.theme.textLight, this.props.theme.textDark],
- });
-
- return (
-
-
- {
- this.fabPressable = el;
- if (this.props.buttonRef) {
- this.props.buttonRef.current = el;
- }
- }}
- accessibilityLabel={this.props.accessibilityLabel}
- role={this.props.role}
- pressDimmingValue={1}
- onPress={(e) => {
- // Drop focus to avoid blue focus ring.
- this.fabPressable.blur();
- this.props.onPress(e);
- }}
- onLongPress={() => {}}
- style={[this.props.themeStyles.floatingActionButton, StyleUtils.getAnimatedFABStyle(rotate, backgroundColor)]}
- >
-
-
-
-
- );
- }
+ }, [props.isActive]);
+
+ useEffect(() => {
+ if (props.isActive === previousIsActive) {
+ return;
+ }
+
+ animateFloatingActionButton();
+ }, [props.isActive, animateFloatingActionButton, previousIsActive]);
+
+ const rotate = animatedValue.current.interpolate({
+ inputRange: [0, 1],
+ outputRange: ['0deg', '135deg'],
+ });
+
+ const backgroundColor = animatedValue.current.interpolate({
+ inputRange: [0, 1],
+ outputRange: [props.theme.success, props.theme.buttonDefaultBG],
+ });
+
+ const fill = animatedValue.current.interpolate({
+ inputRange: [0, 1],
+ outputRange: [props.theme.textLight, props.theme.textDark],
+ });
+
+ return (
+
+
+ {
+ fabPressable.current = el;
+ if (props.buttonRef) {
+ // eslint-disable-next-line no-param-reassign
+ props.buttonRef.current = el;
+ }
+ }}
+ accessibilityLabel={props.accessibilityLabel}
+ role={props.role}
+ pressDimmingValue={1}
+ onPress={(e) => {
+ // Drop focus to avoid blue focus ring.
+ fabPressable.current.blur();
+ props.onPress(e);
+ }}
+ onLongPress={() => {}}
+ style={[props.themeStyles.floatingActionButton, StyleUtils.getAnimatedFABStyle(rotate, backgroundColor)]}
+ >
+
+
+
+
+ );
}
FloatingActionButton.propTypes = propTypes;
@@ -128,4 +126,4 @@ const FloatingActionButtonWithLocalizeWithRef = React.forwardRef((props, ref) =>
FloatingActionButtonWithLocalizeWithRef.displayName = 'FloatingActionButtonWithLocalizeWithRef';
-export default compose(withThemeStyles, withTheme)(FloatingActionButtonWithLocalizeWithRef);
+export default compose(withThemeStyles, withTheme, memo)(FloatingActionButtonWithLocalizeWithRef);