UNPKG

3.3 kBJavaScriptView Raw
1import * as React from 'react';
2import useNavigation from './useNavigation';
3
4/**
5 * Hook to run an effect in a focused screen, similar to `React.useEffect`.
6 * This can be used to perform side-effects such as fetching data or subscribing to events.
7 * The passed callback should be wrapped in `React.useCallback` to avoid running the effect too often.
8 *
9 * @param callback Memoized callback containing the effect, should optionally return a cleanup function.
10 */
11export default function useFocusEffect(effect) {
12 const navigation = useNavigation();
13
14 if (arguments[1] !== undefined) {
15 const message = "You passed a second argument to 'useFocusEffect', but it only accepts one argument. " + "If you want to pass a dependency array, you can use 'React.useCallback':\n\n" + 'useFocusEffect(\n' + ' React.useCallback(() => {\n' + ' // Your code here\n' + ' }, [depA, depB])\n' + ');\n\n' + 'See usage guide: https://reactnavigation.org/docs/use-focus-effect';
16 console.error(message);
17 }
18
19 React.useEffect(() => {
20 let isFocused = false;
21 let cleanup;
22
23 const callback = () => {
24 const destroy = effect();
25
26 if (destroy === undefined || typeof destroy === 'function') {
27 return destroy;
28 }
29
30 if (process.env.NODE_ENV !== 'production') {
31 let message = 'An effect function must not return anything besides a function, which is used for clean-up.';
32
33 if (destroy === null) {
34 message += " You returned 'null'. If your effect does not require clean-up, return 'undefined' (or nothing).";
35 } else if (typeof destroy.then === 'function') {
36 message += "\n\nIt looks like you wrote 'useFocusEffect(async () => ...)' or returned a Promise. " + 'Instead, write the async function inside your effect ' + 'and call it immediately:\n\n' + 'useFocusEffect(\n' + ' React.useCallback(() => {\n' + ' async function fetchData() {\n' + ' // You can await here\n' + ' const response = await MyAPI.getData(someId);\n' + ' // ...\n' + ' }\n\n' + ' fetchData();\n' + ' }, [someId])\n' + ');\n\n' + 'See usage guide: https://reactnavigation.org/docs/use-focus-effect';
37 } else {
38 message += ` You returned '${JSON.stringify(destroy)}'.`;
39 }
40
41 console.error(message);
42 }
43 }; // We need to run the effect on intial render/dep changes if the screen is focused
44
45
46 if (navigation.isFocused()) {
47 cleanup = callback();
48 isFocused = true;
49 }
50
51 const unsubscribeFocus = navigation.addListener('focus', () => {
52 // If callback was already called for focus, avoid calling it again
53 // The focus event may also fire on intial render, so we guard against runing the effect twice
54 if (isFocused) {
55 return;
56 }
57
58 if (cleanup !== undefined) {
59 cleanup();
60 }
61
62 cleanup = callback();
63 isFocused = true;
64 });
65 const unsubscribeBlur = navigation.addListener('blur', () => {
66 if (cleanup !== undefined) {
67 cleanup();
68 }
69
70 cleanup = undefined;
71 isFocused = false;
72 });
73 return () => {
74 if (cleanup !== undefined) {
75 cleanup();
76 }
77
78 unsubscribeFocus();
79 unsubscribeBlur();
80 };
81 }, [effect, navigation]);
82}
83//# sourceMappingURL=useFocusEffect.js.map
\No newline at end of file