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

useFocusEffect / useIsFocused #43

Merged
merged 8 commits into from
Oct 2, 2019
Merged
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
74 changes: 74 additions & 0 deletions src/Hooks.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import {
useState,
useContext,
useEffect,
useLayoutEffect,
useRef,
useCallback,
Expand All @@ -15,6 +16,7 @@ import {
NavigationEventPayload,
EventType,
} from 'react-navigation';
import { BackHandler } from 'react-native';

export function useNavigation<S>(): NavigationScreenProp<S & NavigationRoute> {
const navigation = useContext(NavigationContext) as any; // TODO typing?
Expand Down Expand Up @@ -143,3 +145,75 @@ export function useFocusState() {

return focusState;
}

type EffectCallback = (() => void) | (() => () => void);

// Inspired by same hook from react-navigation v5
// See https://github.com/react-navigation/hooks/issues/39#issuecomment-534694135
export const useFocusEffect = (callback: EffectCallback) => {
const navigation = useNavigation();
const getCallback = useGetter(callback);
slorber marked this conversation as resolved.
Show resolved Hide resolved

useEffect(() => {
let isFocused = false;
let cleanup: (() => void) | void;

if (navigation.isFocused()) {
cleanup = getCallback()();
isFocused = true;
}

const focusSubscription = navigation.addListener('willFocus', () => {
// If callback was already called for focus, avoid calling it again
// The focus event may also fire on intial render, so we guard against runing the effect twice
if (isFocused) {
return;
}

cleanup && cleanup();
cleanup = getCallback()();
isFocused = true;
});

const blurSubscription = navigation.addListener('willBlur', () => {
slorber marked this conversation as resolved.
Show resolved Hide resolved
cleanup && cleanup();
cleanup = undefined;
isFocused = false;
});

return () => {
cleanup && cleanup();
focusSubscription.remove();
blurSubscription.remove();
};
}, [getCallback, navigation]);
};

export const useIsFocused = () => {
const navigation = useNavigation();
const [focused, setFocused] = useState(navigation.isFocused());
slorber marked this conversation as resolved.
Show resolved Hide resolved

useEffect(() => {
const focusSubscription = navigation.addListener('willFocus', () =>
setFocused(true),
);
const blurSubscription = navigation.addListener('willBlur', () =>
setFocused(false),
);
return () => {
focusSubscription.remove();
blurSubscription.remove();
};
}, [setFocused]);
slorber marked this conversation as resolved.
Show resolved Hide resolved

return focused;
};

export const useBackHandler = (backHandler: () => boolean) => {
useFocusEffect(() => {
slorber marked this conversation as resolved.
Show resolved Hide resolved
BackHandler.addEventListener('hardwareBackPress', backHandler);
return () => {
BackHandler.removeEventListener('hardwareBackPress', backHandler);
};
});
};