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