Skip to content

Commit 920f4ab

Browse files
committed
feat: provide way to inject focus effect
1 parent 7e7eb94 commit 920f4ab

3 files changed

Lines changed: 48 additions & 25 deletions

File tree

src/react-native/focus-effect.ts

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
import { useEffect } from "react";
2+
3+
const getDefaultFocusEffectFactory = (): ((cb: () => void) => void) => {
4+
try {
5+
return require("expo-router").useFocusEffect;
6+
} catch {
7+
// Nothing we can do about it, it's not installed in the project.
8+
}
9+
10+
try {
11+
return require("@react-navigation/native").useFocusEffect;
12+
} catch {
13+
// Nothing we can do about it, it's not installed in the project.
14+
}
15+
16+
console.warn(
17+
"[react-native-grab] No supported router found — falling back to useEffect. This may cause issues. Provide a custom focus effect using the setFocusEffect function.",
18+
);
19+
20+
const useFallbackFocusEffect = (cb: () => void) => {
21+
useEffect(() => {
22+
return cb();
23+
}, [cb]);
24+
};
25+
26+
return useFallbackFocusEffect;
27+
};
28+
29+
let cachedFocusEffect: ((cb: () => void) => void) | null = null;
30+
31+
export const getFocusEffect = (): ((cb: () => void) => void) => {
32+
if (!cachedFocusEffect) {
33+
cachedFocusEffect = getDefaultFocusEffectFactory();
34+
}
35+
36+
return cachedFocusEffect;
37+
};
38+
39+
export const setFocusEffect = (impl: (cb: () => void) => void) => {
40+
cachedFocusEffect = impl;
41+
};

src/react-native/grab-screen.tsx

Lines changed: 3 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,9 @@
1-
import { useCallback, useEffect, useRef } from "react";
1+
import { useCallback, useRef } from "react";
22
import { View, type ViewProps } from "react-native";
33
import { setFocusedScreenRef } from "./containers";
4+
import { getFocusEffect } from "./focus-effect";
45

5-
const getFocusEffectImpl = (): ((cb: () => void) => void) => {
6-
try {
7-
return require("expo-router").useFocusEffect;
8-
} catch {
9-
// Nothing we can do about it, it's not installed in the project.
10-
}
11-
12-
try {
13-
return require("@react-navigation/native").useFocusEffect;
14-
} catch {
15-
// Nothing we can do about it, it's not installed in the project.
16-
}
17-
18-
// No supported router found — fall back to useEffect
19-
return (cb: () => void) => {
20-
// eslint-disable-next-line react-hooks/rules-of-hooks
21-
useEffect(() => {
22-
const cleanup = cb();
23-
return typeof cleanup === "function" ? cleanup : undefined;
24-
}, [cb]);
25-
};
26-
};
27-
28-
const useFocusEffect = getFocusEffectImpl();
6+
const useFocusEffect = getFocusEffect();
297

308
export type ReactNativeGrabScreenProps = ViewProps;
319

src/react-native/index.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,3 +30,7 @@ export const ReactNativeGrabContextProvider: React.ComponentType<ReactNativeGrab
3030
export const enableGrabbing: () => void = __DEV__
3131
? require("./grab-controller").enableGrabbing
3232
: noop;
33+
34+
export const setFocusEffect: (impl: (cb: () => void) => void) => void = __DEV__
35+
? require("./focus-effect").setFocusEffect
36+
: noop;

0 commit comments

Comments
 (0)