Skip to content
This repository was archived by the owner on Dec 3, 2022. It is now read-only.

Commit 3304438

Browse files
committed
add useFocusEffect useIsFocused useBackHandler, inspired by v5 code
1 parent 11aa5b1 commit 3304438

File tree

1 file changed

+75
-0
lines changed

1 file changed

+75
-0
lines changed

src/Hooks.ts

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import {
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

1921
export 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

Comments
 (0)