1
1
import React from 'react' ;
2
- import { AsyncStorage , Linking , Platform , BackHandler } from 'react-native' ;
3
-
2
+ import { Linking , Platform , BackHandler } from 'react-native' ;
4
3
import {
5
4
NavigationActions ,
6
5
pathUtils ,
@@ -17,11 +16,26 @@ function isStateful(props) {
17
16
}
18
17
19
18
function validateProps ( props ) {
19
+ if ( props . persistenceKey ) {
20
+ console . warn (
21
+ 'You passed persistenceKey prop to a navigator. ' +
22
+ 'The persistenceKey prop was replaced by a more flexible persistence mechanism, ' +
23
+ 'please see the navigation state persistence docs for more information. ' +
24
+ 'Passing the persistenceKey prop is a no-op.'
25
+ ) ;
26
+ }
20
27
if ( isStateful ( props ) ) {
21
28
return ;
22
29
}
23
- // eslint-disable-next-line no-unused-vars
24
- const { navigation, screenProps, ...containerProps } = props ;
30
+ /* eslint-disable no-unused-vars */
31
+ const {
32
+ navigation,
33
+ screenProps,
34
+ persistNavigationState,
35
+ loadNavigationState,
36
+ ...containerProps
37
+ } = props ;
38
+ /* eslint-enable no-unused-vars */
25
39
26
40
const keys = Object . keys ( containerProps ) ;
27
41
@@ -35,6 +49,13 @@ function validateProps(props) {
35
49
'navigator should maintain its own state, do not pass a navigation prop.'
36
50
) ;
37
51
}
52
+ invariant (
53
+ ( persistNavigationState === undefined &&
54
+ loadNavigationState === undefined ) ||
55
+ ( typeof persistNavigationState === 'function' &&
56
+ typeof loadNavigationState === 'function' ) ,
57
+ 'both persistNavigationState and loadNavigationState must either be undefined, or be functions'
58
+ ) ;
38
59
}
39
60
40
61
// Track the number of stateful container instances. Warn if >0 and not using the
@@ -100,7 +121,7 @@ export default function createNavigationContainer(Component) {
100
121
101
122
this . state = {
102
123
nav :
103
- this . _isStateful ( ) && ! props . persistenceKey
124
+ this . _isStateful ( ) && ! props . loadNavigationState
104
125
? Component . router . getStateForAction ( this . _initialAction )
105
126
: null ,
106
127
} ;
@@ -210,35 +231,30 @@ export default function createNavigationContainer(Component) {
210
231
Linking . addEventListener ( 'url' , this . _handleOpenURL ) ;
211
232
212
233
// Pull out anything that can impact state
213
- const { persistenceKey, uriPrefix, enableURLHandling } = this . props ;
214
234
let parsedUrl = null ;
215
- let startupStateJSON = null ;
216
- if ( enableURLHandling !== false ) {
217
- startupStateJSON =
218
- persistenceKey && ( await AsyncStorage . getItem ( persistenceKey ) ) ;
219
- const url = await Linking . getInitialURL ( ) ;
220
- parsedUrl = url && urlToPathAndParams ( url , uriPrefix ) ;
235
+ let userProvidedStartupState = null ;
236
+ if ( this . props . enableURLHandling !== false ) {
237
+ ( {
238
+ parsedUrl ,
239
+ userProvidedStartupState ,
240
+ } = await this . getStartupParams ( ) ) ;
221
241
}
222
242
223
243
// Initialize state. This must be done *after* any async code
224
244
// so we don't end up with a different value for this.state.nav
225
245
// due to changes while async function was resolving
226
246
let action = this . _initialAction ;
227
247
let startupState = this . state . nav ;
228
- if ( ! startupState ) {
248
+ if ( ! startupState && ! userProvidedStartupState ) {
229
249
! ! process . env . REACT_NAV_LOGGING &&
230
250
console . log ( 'Init new Navigation State' ) ;
231
251
startupState = Component . router . getStateForAction ( action ) ;
232
252
}
233
253
234
- // Pull persisted state from AsyncStorage
235
- if ( startupStateJSON ) {
236
- try {
237
- startupState = JSON . parse ( startupStateJSON ) ;
238
- _reactNavigationIsHydratingState = true ;
239
- } catch ( e ) {
240
- /* do nothing */
241
- }
254
+ // Pull user-provided persisted state
255
+ if ( userProvidedStartupState ) {
256
+ startupState = userProvidedStartupState ;
257
+ _reactNavigationIsHydratingState = true ;
242
258
}
243
259
244
260
// Pull state out of URL
@@ -284,11 +300,28 @@ export default function createNavigationContainer(Component) {
284
300
} ) ;
285
301
}
286
302
303
+ async getStartupParams ( ) {
304
+ const { uriPrefix, loadNavigationState } = this . props ;
305
+ let url , loadedNavState ;
306
+ try {
307
+ [ url , loadedNavState ] = await Promise . all ( [
308
+ Linking . getInitialURL ( ) ,
309
+ loadNavigationState && loadNavigationState ( ) ,
310
+ ] ) ;
311
+ } catch ( err ) {
312
+ // ignore
313
+ }
314
+ return {
315
+ parsedUrl : url && urlToPathAndParams ( url , uriPrefix ) ,
316
+ userProvidedStartupState : loadedNavState ,
317
+ } ;
318
+ }
319
+
287
320
componentDidCatch ( e ) {
288
321
if ( _reactNavigationIsHydratingState ) {
289
322
_reactNavigationIsHydratingState = false ;
290
323
console . warn (
291
- 'Uncaught exception while starting app from persisted navigation state! Trying to render again with a fresh navigation state..'
324
+ 'Uncaught exception while starting app from persisted navigation state! Trying to render again with a fresh navigation state... '
292
325
) ;
293
326
this . dispatch ( NavigationActions . init ( ) ) ;
294
327
} else {
@@ -297,11 +330,16 @@ export default function createNavigationContainer(Component) {
297
330
}
298
331
299
332
_persistNavigationState = async nav => {
300
- const { persistenceKey } = this . props ;
301
- if ( ! persistenceKey ) {
302
- return ;
333
+ const { persistNavigationState } = this . props ;
334
+ if ( persistNavigationState ) {
335
+ try {
336
+ await persistNavigationState ( nav ) ;
337
+ } catch ( err ) {
338
+ console . warn (
339
+ 'Uncaught exception while calling persistNavigationState()! You should handle exceptions thrown from persistNavigationState(), ignoring them may result in undefined behavior.'
340
+ ) ;
341
+ }
303
342
}
304
- await AsyncStorage . setItem ( persistenceKey , JSON . stringify ( nav ) ) ;
305
343
} ;
306
344
307
345
componentWillUnmount ( ) {
0 commit comments