UNPKG

5.28 kBJavaScriptView Raw
1"use strict";
2
3Object.defineProperty(exports, "__esModule", {
4 value: true
5});
6exports.default = useNavigationCache;
7
8var _routers = require("@react-navigation/routers");
9
10var React = _interopRequireWildcard(require("react"));
11
12var _NavigationBuilderContext = _interopRequireDefault(require("./NavigationBuilderContext"));
13
14function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
15
16function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function (nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }
17
18function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
19
20/**
21 * Hook to cache navigation objects for each screen in the navigator.
22 * It's important to cache them to make sure navigation objects don't change between renders.
23 * This lets us apply optimizations like `React.memo` to minimize re-rendering screens.
24 */
25function useNavigationCache(_ref) {
26 let {
27 state,
28 getState,
29 navigation,
30 setOptions,
31 router,
32 emitter
33 } = _ref;
34 const {
35 stackRef
36 } = React.useContext(_NavigationBuilderContext.default); // Cache object which holds navigation objects for each screen
37 // We use `React.useMemo` instead of `React.useRef` coz we want to invalidate it when deps change
38 // In reality, these deps will rarely change, if ever
39
40 const cache = React.useMemo(() => ({
41 current: {}
42 }), // eslint-disable-next-line react-hooks/exhaustive-deps
43 [getState, navigation, setOptions, router, emitter]);
44 const actions = { ...router.actionCreators,
45 ..._routers.CommonActions
46 };
47 cache.current = state.routes.reduce((acc, route) => {
48 const previous = cache.current[route.key];
49
50 if (previous) {
51 // If a cached navigation object already exists, reuse it
52 acc[route.key] = previous;
53 } else {
54 // eslint-disable-next-line @typescript-eslint/no-unused-vars
55 const {
56 emit,
57 ...rest
58 } = navigation;
59
60 const dispatch = thunk => {
61 const action = typeof thunk === 'function' ? thunk(getState()) : thunk;
62
63 if (action != null) {
64 navigation.dispatch({
65 source: route.key,
66 ...action
67 });
68 }
69 };
70
71 const withStack = callback => {
72 let isStackSet = false;
73
74 try {
75 if (process.env.NODE_ENV !== 'production' && stackRef && !stackRef.current) {
76 // Capture the stack trace for devtools
77 stackRef.current = new Error().stack;
78 isStackSet = true;
79 }
80
81 callback();
82 } finally {
83 if (isStackSet && stackRef) {
84 stackRef.current = undefined;
85 }
86 }
87 };
88
89 const helpers = Object.keys(actions).reduce((acc, name) => {
90 acc[name] = function () {
91 for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
92 args[_key] = arguments[_key];
93 }
94
95 return withStack(() => // @ts-expect-error: name is a valid key, but TypeScript is dumb
96 dispatch(actions[name](...args)));
97 };
98
99 return acc;
100 }, {});
101 acc[route.key] = { ...rest,
102 ...helpers,
103 // FIXME: too much work to fix the types for now
104 ...emitter.create(route.key),
105 dispatch: thunk => withStack(() => dispatch(thunk)),
106 getParent: id => {
107 if (id !== undefined && id === rest.getId()) {
108 // If the passed id is the same as the current navigation id,
109 // we return the cached navigation object for the relevant route
110 return acc[route.key];
111 }
112
113 return rest.getParent(id);
114 },
115 setOptions: options => setOptions(o => ({ ...o,
116 [route.key]: { ...o[route.key],
117 ...options
118 }
119 })),
120 isFocused: () => {
121 const state = getState();
122
123 if (state.routes[state.index].key !== route.key) {
124 return false;
125 } // If the current screen is focused, we also need to check if parent navigator is focused
126 // This makes sure that we return the focus state in the whole tree, not just this navigator
127
128
129 return navigation ? navigation.isFocused() : true;
130 }
131 };
132 }
133
134 return acc;
135 }, {});
136 return cache.current;
137}
138//# sourceMappingURL=useNavigationCache.js.map
\No newline at end of file