Skip to content

Commit 93b8daa

Browse files
committed
Improve auth flow docs
1 parent 7c12bbe commit 93b8daa

File tree

1 file changed

+105
-45
lines changed

1 file changed

+105
-45
lines changed

versioned_docs/version-7.x/auth-flow.md

+105-45
Original file line numberDiff line numberDiff line change
@@ -81,9 +81,21 @@ function SignInScreen() {
8181

8282
Here, for each screen, we have defined a condition using the `if` property which takes a hook. The hook returns a boolean value indicating whether the user is signed in or not. If the hook returns `true`, the screen will be available, otherwise it won't.
8383

84-
When `useIsSignedIn` returns `true`, React Navigation will only use the `Home` screen, and when it returns `false`, React Navigation will use the `SignIn` screen. This makes it impossible to navigate to the `Home` when the user is not signed in, and to `SignIn` when the user is signed in.
84+
This means:
8585

86-
The magic happens when the value returned by `useIsSignedin` changes. Let's say, initially `useIsSignedIn` returns `false`. This means that `SignIn` screens is shown. After the user signs in, the return value of `useIsSignedIn` will change to `true`. React Navigation will see that the `SignIn` screen is no longer defined and so it will remove it. Then it'll show the `Home` screen automatically because that's the first screen defined when `useIsSignedIn` returns `true`.
86+
- When `useIsSignedIn` returns `true`, React Navigation will only use the `Home` screen, since it's the only screen matching the condition.
87+
- Similarly, when `useIsSignedOut` returns `true`, React Navigation will use the `SignIn` screen.
88+
89+
This makes it impossible to navigate to the `Home` when the user is not signed in, and to `SignIn` when the user is signed in.
90+
91+
When the values returned by `useIsSignedin` and `useIsSignedOut` change, the screens matching the condition will change:
92+
93+
- Let's say, initially `useIsSignedOut` returns `true`. This means that `SignIn` screens is shown.
94+
- After the user signs in, the return value of `useIsSignedIn` will change to `true` and `useIsSignedOut` will change to `false`, which means:
95+
- React Navigation will see that the `SignIn` screen is no longer matches the condition, so it will remove the screen.
96+
- Then it'll show the `Home` screen automatically because that's the first screen available when `useIsSignedIn` returns `true`.
97+
98+
The order of the screens matters when there are multiple screens matching the condition. For example, if there are two screens matching `useIsSignedIn`, the first screen will be shown when the condition is `true`.
8799

88100
## Define the hooks
89101

@@ -104,8 +116,7 @@ function useIsSignedIn() {
104116
}
105117

106118
function useIsSignedOut() {
107-
const isSignedIn = React.useContext(SignInContext);
108-
return !isSignedIn;
119+
return !useIsSignedIn();
109120
}
110121
```
111122

@@ -152,11 +163,21 @@ function SignInScreen() {
152163

153164
Here, we have conditionally defined the screens based on the value of `isSignedIn`.
154165

155-
When `isSignedIn` is `true`, React Navigation will only see the `Home` screen, and when it returns `false`, React Navigation will see the `SignIn` screen. This makes it impossible to navigate to the `Home` when the user is not signed in, and to `SignIn` when the user is signed in.
166+
This means:
167+
168+
- When `isSignedIn` is `true`, React Navigation will only see the `Home` screen, since it's the only screen defined based on the condition.
169+
- Similarly, when `isSignedIn` is `false`, React Navigation will only see the `SignIn` screen.
156170

157-
This pattern has been in use by other routing libraries such as React Router for a long time, and is commonly known as "Protected routes". Here, our screens which need the user to be signed in are "protected" and cannot be navigated to by other means if the user is not signed in.
171+
This makes it impossible to navigate to the `Home` when the user is not signed in, and to `SignIn` when the user is signed in.
158172

159-
The magic happens when the value of `isSignedin` changes. Let's say, initially `isSignedIn` returns `false`. This means that `SignIn` screens is shown. After the user signs in, the value of `isSignedIn` will change to `true`. React Navigation will see that the `SignIn` screen is no longer defined and so it will remove it. Then it'll show the `Home` screen automatically because that's the first screen defined when `isSignedIn` is `true`.
173+
When the value of `isSignedin` changes, the screens defined based on the condition will change:
174+
175+
- Let's say, initially `isSignedin` is `false`. This means that `SignIn` screens is shown.
176+
- After the user signs in, the value of `isSignedin` will change to `true`, which means:
177+
- React Navigation will see that the `SignIn` screen is no longer defined, so it will remove the screen.
178+
- Then it'll show the `Home` screen automatically because that's the first screen defined when `isSignedin` returns `true`.
179+
180+
The order of the screens matters when there are multiple screens matching the condition. For example, if there are two screens defined based on `isSignedin`, the first screen will be shown when the condition is `true`.
160181

161182
</TabItem>
162183
</Tabs>
@@ -194,10 +215,46 @@ const RootStack = createNativeStackNavigator({
194215
const Navigation = createStaticNavigation(RootStack);
195216
```
196217

218+
</TabItem>
219+
<TabItem value="dynamic" label="Dynamic">
220+
221+
```js
222+
const Stack = createNativeStackNavigator();
223+
224+
export default function App() {
225+
const isSignedIn = true;
226+
227+
return (
228+
<NavigationContainer>
229+
<Stack.Navigator>
230+
{isSignedIn ? (
231+
<Stack.Screen
232+
name="SignIn"
233+
component={SimpleSignInScreen}
234+
options={{
235+
title: 'Sign in',
236+
}}
237+
initialParams={{ setUserToken }}
238+
/>
239+
) : (
240+
<Stack.Screen name="Home" component={HomeScreen} />
241+
)}
242+
</Stack.Navigator>
243+
</NavigationContainer>
244+
);
245+
}
246+
```
247+
248+
</TabItem>
249+
</Tabs>
250+
197251
Notice how we have only defined the `Home` and `SignIn` screens here, and not the `SplashScreen`. The `SplashScreen` should be rendered before we render any navigators so that we don't render incorrect screens before we know whether the user is signed in or not.
198252

199253
When we use this in our component, it'd look something like this:
200254

255+
<Tabs groupId="config" queryString="config">
256+
<TabItem value="static" label="Static" default>
257+
201258
```js
202259
if (isLoading) {
203260
// We haven't finished checking for the token yet
@@ -213,37 +270,6 @@ return (
213270
);
214271
```
215272

216-
In the above snippet, `isLoading` means that we're still checking if we have a token. This can usually be done by checking if we have a token in `SecureStore` and validating the token.
217-
218-
Next, we're exposing the sign in status via the `SignInContext` so that it's available to the `useIsSignedIn` and `useIsSignedOut` hooks.
219-
220-
In the above example, we have one screen for each case. But you could also define multiple screens. For example, you probably want to define password reset, signup, etc screens as well when the user isn't signed in. Similarly for the screens accessible after sign in, you probably have more than one screen. We can use [`groups`](static-configuration.md#groups) to define multiple screens:
221-
222-
```js
223-
const RootStack = createNativeStackNavigator({
224-
screens: {
225-
// Common screens
226-
},
227-
groups: {
228-
SignedIn: {
229-
if: useIsSignedIn,
230-
screens: {
231-
Home: HomeScreen,
232-
Profile: ProfileScreen,
233-
},
234-
},
235-
SignedOut: {
236-
if: useIsSignedOut,
237-
screens: {
238-
SignIn: SignInScreen,
239-
SignUp: SignUpScreen,
240-
ResetPassword: ResetPasswordScreen,
241-
},
242-
},
243-
},
244-
});
245-
```
246-
247273
</TabItem>
248274
<TabItem value="dynamic" label="Dynamic">
249275

@@ -275,14 +301,49 @@ return (
275301
);
276302
```
277303

304+
</TabItem>
305+
</Tabs>
306+
278307
In the above snippet, `isLoading` means that we're still checking if we have a token. This can usually be done by checking if we have a token in `SecureStore` and validating the token.
279308

280-
The main thing to notice is that we're conditionally defining screens based on these state variables:
309+
Next, we're exposing the sign in status via the `SignInContext` so that it's available to the `useIsSignedIn` and `useIsSignedOut` hooks.
310+
311+
In the above example, we have one screen for each case. But you could also define multiple screens. For example, you probably want to define password reset, signup, etc screens as well when the user isn't signed in. Similarly for the screens accessible after sign in, you probably have more than one screen.
312+
313+
<Tabs groupId="config" queryString="config">
314+
<TabItem value="static" label="Static" default>
315+
316+
We can use [`groups`](static-configuration.md#groups) to define multiple screens:
317+
318+
```js
319+
const RootStack = createNativeStackNavigator({
320+
screens: {
321+
// Common screens
322+
},
323+
groups: {
324+
SignedIn: {
325+
if: useIsSignedIn,
326+
screens: {
327+
Home: HomeScreen,
328+
Profile: ProfileScreen,
329+
},
330+
},
331+
SignedOut: {
332+
if: useIsSignedOut,
333+
screens: {
334+
SignIn: SignInScreen,
335+
SignUp: SignUpScreen,
336+
ResetPassword: ResetPasswordScreen,
337+
},
338+
},
339+
},
340+
});
341+
```
281342

282-
- `SignIn` screen is only defined if `userToken` is `null` (user is not signed in)
283-
- `Home` screen is only defined if `userToken` is non-null (user is signed in)
343+
</TabItem>
344+
<TabItem value="dynamic" label="Dynamic">
284345

285-
Here, we're conditionally defining one screen for each case. But you could also define multiple screens. For example, you probably want to define password reset, signup, etc screens as well when the user isn't signed in. Similarly, for the screens accessible after signing in, you probably have more than one screen. We can use [`React.Fragment`](https://react.dev/reference/react/Fragment) or [`Group`](group.md) to define multiple screens:
346+
We can use [`React.Fragment`](https://react.dev/reference/react/Fragment) or [`Group`](group.md) to define multiple screens:
286347

287348
```js
288349
isSignedIn ? (
@@ -301,7 +362,7 @@ isSignedIn ? (
301362

302363
:::tip
303364

304-
If you have both your login-related screens and rest of the screens in two different Stack navigators and render them conditionally, we recommend to use a single Stack navigator and place the conditional inside instead of using 2 different navigators. This makes it possible to have a proper transition animation during login/logout.
365+
Instead of having your login-related screens and rest of the screens in two different Stack navigators and render them conditionally, we recommend to use a single Stack navigator and place the conditional inside. This makes it possible to have a proper transition animation during login/logout.
305366

306367
:::
307368

@@ -368,8 +429,7 @@ function useIsSignedIn() {
368429
}
369430

370431
function useIsSignedOut() {
371-
const isSignedIn = React.useContext(SignInContext);
372-
return !isSignedIn;
432+
return !useIsSignedIn();
373433
}
374434

375435
function SplashScreen() {

0 commit comments

Comments
 (0)