11import {
22 useState ,
33 useContext ,
4+ useEffect ,
45 useLayoutEffect ,
56 useRef ,
67 useCallback ,
@@ -15,6 +16,7 @@ import {
1516 NavigationEventPayload ,
1617 EventType ,
1718} from 'react-navigation' ;
19+ import { BackHandler } from 'react-native' ;
1820
1921export function useNavigation < S > ( ) : NavigationScreenProp < S & NavigationRoute > {
2022 const navigation = useContext ( NavigationContext ) as any ; // TODO typing?
@@ -143,3 +145,76 @@ export function useFocusState() {
143145
144146 return focusState ;
145147}
148+
149+
150+ type EffectCallback = ( ( ) => void ) | ( ( ) => ( ) => void ) ;
151+
152+ // Inspired by same hook from react-navigation v5
153+ // See https://github.com/react-navigation/hooks/issues/39#issuecomment-534694135
154+ export const useFocusEffect = ( callback : EffectCallback ) => {
155+ const navigation = useNavigation ( ) ;
156+ const getCallback = useGetter ( callback ) ;
157+
158+ useEffect ( ( ) => {
159+ let isFocused = false ;
160+ let cleanup : ( ( ) => void ) | void ;
161+
162+ if ( navigation . isFocused ( ) ) {
163+ cleanup = getCallback ( ) ( ) ;
164+ isFocused = true ;
165+ }
166+
167+ const focusSubscription = navigation . addListener ( 'willFocus' , ( ) => {
168+ // If callback was already called for focus, avoid calling it again
169+ // The focus event may also fire on intial render, so we guard against runing the effect twice
170+ if ( isFocused ) {
171+ return ;
172+ }
173+
174+ cleanup && cleanup ( ) ;
175+ cleanup = getCallback ( ) ( ) ;
176+ isFocused = true ;
177+ } ) ;
178+
179+ const blurSubscription = navigation . addListener ( 'willBlur' , ( ) => {
180+ cleanup && cleanup ( ) ;
181+ cleanup = undefined ;
182+ isFocused = false ;
183+ } ) ;
184+
185+ return ( ) => {
186+ cleanup && cleanup ( ) ;
187+ focusSubscription . remove ( ) ;
188+ blurSubscription . remove ( ) ;
189+ } ;
190+ } , [ getCallback , navigation ] ) ;
191+ } ;
192+
193+ export const useIsFocused = ( ) => {
194+ const navigation = useNavigation ( ) ;
195+ const [ focused , setFocused ] = useState ( navigation . isFocused ( ) ) ;
196+
197+ useEffect ( ( ) => {
198+ const focusSubscription = navigation . addListener ( 'willFocus' , ( ) =>
199+ setFocused ( true ) ,
200+ ) ;
201+ const blurSubscription = navigation . addListener ( 'willBlur' , ( ) =>
202+ setFocused ( false ) ,
203+ ) ;
204+ return ( ) => {
205+ focusSubscription . remove ( ) ;
206+ blurSubscription . remove ( ) ;
207+ } ;
208+ } , [ setFocused ] ) ;
209+
210+ return focused ;
211+ } ;
212+
213+ export const useBackHandler = ( backHandler : ( ) => boolean ) => {
214+ useFocusEffect ( ( ) => {
215+ BackHandler . addEventListener ( 'hardwareBackPress' , backHandler ) ;
216+ return ( ) => {
217+ BackHandler . removeEventListener ( 'hardwareBackPress' , backHandler ) ;
218+ } ;
219+ } ) ;
220+ } ;
0 commit comments