diff --git a/src/components/GrowlNotification/index.js b/src/components/GrowlNotification/index.js
index b995d0ec7039..60bd1bf00587 100644
--- a/src/components/GrowlNotification/index.js
+++ b/src/components/GrowlNotification/index.js
@@ -1,6 +1,6 @@
-import React, {Component} from 'react';
-import {View, Animated} from 'react-native';
+import React, {forwardRef, useCallback, useEffect, useImperativeHandle, useRef, useState} from 'react';
import {Directions, FlingGestureHandler, State} from 'react-native-gesture-handler';
+import {View, Animated} from 'react-native';
import colors from '../../styles/colors';
import Text from '../Text';
import Icon from '../Icon';
@@ -30,23 +30,11 @@ const INACTIVE_POSITION_Y = -255;
const PressableWithoutFeedback = Pressables.PressableWithoutFeedback;
-class GrowlNotification extends Component {
- constructor(props) {
- super(props);
-
- this.state = {
- bodyText: '',
- type: 'success',
- translateY: new Animated.Value(INACTIVE_POSITION_Y),
- };
-
- this.show = this.show.bind(this);
- this.fling = this.fling.bind(this);
- }
-
- componentDidMount() {
- Growl.setIsReady();
- }
+function GrowlNotification(_, ref) {
+ const translateY = useRef(new Animated.Value(INACTIVE_POSITION_Y)).current;
+ const [bodyText, setBodyText] = useState('');
+ const [type, setType] = useState('success');
+ const [duration, setDuration] = useState();
/**
* Show the growl notification
@@ -55,65 +43,83 @@ class GrowlNotification extends Component {
* @param {String} type
* @param {Number} duration
*/
- show(bodyText, type, duration) {
- this.setState(
- {
- bodyText,
- type,
- },
- () => {
- this.fling(0);
- setTimeout(() => {
- this.fling(INACTIVE_POSITION_Y);
- }, duration);
- },
- );
- }
+ const show = useCallback((text, growlType, growlDuration) => {
+ setBodyText(text);
+ setType(growlType);
+ setDuration(growlDuration);
+ }, []);
/**
* Animate growl notification
*
* @param {Number} val
*/
- fling(val = INACTIVE_POSITION_Y) {
- Animated.spring(this.state.translateY, {
- toValue: val,
- duration: 80,
- useNativeDriver: true,
- }).start();
- }
+ const fling = useCallback(
+ (val = INACTIVE_POSITION_Y) => {
+ Animated.spring(translateY, {
+ toValue: val,
+ duration: 80,
+ useNativeDriver: true,
+ }).start();
+ },
+ [translateY],
+ );
- render() {
- return (
- {
- if (nativeEvent.state !== State.ACTIVE) {
- return;
- }
+ useImperativeHandle(
+ ref,
+ () => ({
+ show,
+ }),
+ [show],
+ );
- this.fling(INACTIVE_POSITION_Y);
- }}
- >
-
-
- this.fling(INACTIVE_POSITION_Y)}
- >
-
-
- {this.state.bodyText}
-
-
-
-
-
- );
- }
+ useEffect(() => {
+ Growl.setIsReady();
+ }, []);
+
+ useEffect(() => {
+ if (!duration) {
+ return;
+ }
+
+ fling(0);
+ setTimeout(() => {
+ fling();
+ setDuration(undefined);
+ }, duration);
+ }, [duration, fling]);
+
+ return (
+ {
+ if (nativeEvent.state !== State.ACTIVE) {
+ return;
+ }
+
+ fling();
+ }}
+ >
+
+
+ fling()}
+ >
+
+
+ {bodyText}
+
+
+
+
+
+ );
}
-export default GrowlNotification;
+GrowlNotification.displayName = 'GrowlNotification';
+
+export default forwardRef(GrowlNotification);