Skip to content

Commit 7c12bbe

Browse files
committed
Update docs
1 parent 5e6e25e commit 7c12bbe

File tree

1 file changed

+57
-128
lines changed

1 file changed

+57
-128
lines changed

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

+57-128
Original file line numberDiff line numberDiff line change
@@ -30,12 +30,12 @@ We want the following behavior from our authentication flow:
3030

3131
## How it will work
3232

33-
We can configure different screens to be available based on some condition. For example, if the user is signed in, we can define `Home`, `Profile`, `Settings` etc. If the user is not signed in, we can define `SignIn` and `SignUp` screens.
33+
We can configure different screens to be available based on some condition. For example, if the user is signed in, we want `Home` to be available. If the user is not signed in, we want `SignIn` to be available.
3434

3535
<Tabs groupId="config" queryString="config">
3636
<TabItem value="static" label="Static" default>
3737

38-
```js name="Customizing tabs appearance" snack
38+
```js name="Authentication flow" snack
3939
import * as React from 'react';
4040
import { View } from 'react-native';
4141
import { createStaticNavigation } from '@react-navigation/native';
@@ -50,36 +50,15 @@ const useIsSignedOut = () => {
5050
};
5151

5252
// codeblock-focus-start
53-
const signedInStack = createNativeStackNavigator({
54-
screens: {
55-
Home: HomeScreen,
56-
Profile: ProfileScreen,
57-
Settings: SettingsScreen,
58-
},
59-
});
60-
61-
const signedOutStack = createNativeStackNavigator({
62-
screens: {
63-
SignIn: SignInScreen,
64-
SignUp: SignUpScreen,
65-
},
66-
});
67-
6853
const RootStack = createNativeStackNavigator({
6954
screens: {
70-
LoggedIn: {
55+
Home: {
7156
if: useIsSignedIn,
72-
screen: signedInStack,
73-
options: {
74-
headerShown: false,
75-
},
57+
screen: HomeScreen,
7658
},
77-
LoggedOut: {
59+
SignIn: {
7860
if: useIsSignedOut,
79-
screen: signedOutStack,
80-
options: {
81-
headerShown: false,
82-
},
61+
screen: SignInScreen,
8362
},
8463
},
8564
});
@@ -95,150 +74,96 @@ function HomeScreen() {
9574
return <View />;
9675
}
9776

98-
function ProfileScreen() {
77+
function SignInScreen() {
9978
return <View />;
10079
}
80+
```
10181

102-
function SettingsScreen() {
103-
return <View />;
104-
}
82+
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.
10583

106-
function SignInScreen() {
107-
return <View />;
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.
85+
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`.
87+
88+
## Define the hooks
89+
90+
To implement the `useIsSignedIn` and `useIsSignedOut` hooks, we can start by creating a context to store the authentication state. Let's call it `SignInContext`:
91+
92+
```js
93+
import * as React from 'react';
94+
95+
const SignInContext = React.createContext();
96+
```
97+
98+
Then we can implement the `useIsSignedIn` and `useIsSignedOut` hooks as follows:
99+
100+
```js
101+
function useIsSignedIn() {
102+
const isSignedIn = React.useContext(SignInContext);
103+
return isSignedIn;
108104
}
109105

110-
function SignUpScreen() {
111-
return <View />;
106+
function useIsSignedOut() {
107+
const isSignedIn = React.useContext(SignInContext);
108+
return !isSignedIn;
112109
}
113110
```
114111

112+
We'll discuss how to provide the context value later.
113+
115114
</TabItem>
116115

117116
<TabItem value="dynamic" label="Dynamic">
118117

119-
```js name="Customizing tabs appearance" snack
118+
```js name="Authentication flow" snack
120119
import * as React from 'react';
121120
import { View } from 'react-native';
122121
import { NavigationContainer } from '@react-navigation/native';
123122
import { createNativeStackNavigator } from '@react-navigation/native-stack';
124123

125124
const Stack = createNativeStackNavigator();
126125

127-
const useIsSignedIn = () => {
128-
return true;
129-
};
130-
131-
const useIsSignedOut = () => {
132-
return !useIsSignedIn();
133-
};
134-
135126
export default function App() {
136-
// codeblock-focus-start
137-
const isSignedIn = useIsSignedIn();
127+
const isSignedIn = true;
138128

139129
return (
140130
<NavigationContainer>
141131
<Stack.Navigator>
132+
// codeblock-focus-start
142133
{isSignedIn ? (
143-
<Stack.Group>
144-
<Stack.Screen name="Home" component={HomeScreen} />
145-
<Stack.Screen name="Profile" component={ProfileScreen} />
146-
<Stack.Screen name="Settings" component={SettingsScreen} />
147-
</Stack.Group>
134+
<Stack.Screen name="Home" component={HomeScreen} />
148135
) : (
149-
<Stack.Group>
150-
<Stack.Screen name="SignIn" component={SignInScreen} />
151-
<Stack.Screen name="SignUp" component={SignUpScreen} />
152-
</Stack.Group>
136+
<Stack.Screen name="SignIn" component={SignInScreen} />
153137
)}
138+
// codeblock-focus-end
154139
</Stack.Navigator>
155140
</NavigationContainer>
156141
);
157-
// codeblock-focus-end
158142
}
159143

160144
function HomeScreen() {
161145
return <View />;
162146
}
163147

164-
function ProfileScreen() {
165-
return <View />;
166-
}
167-
168-
function SettingsScreen() {
169-
return <View />;
170-
}
171-
172148
function SignInScreen() {
173149
return <View />;
174150
}
175-
176-
function SignUpScreen() {
177-
return <View />;
178-
}
179151
```
180152

181-
</TabItem>
182-
</Tabs>
153+
Here, we have conditionally defined the screens based on the value of `isSignedIn`.
183154

184-
When `useIsSignedIn` returns `true`, React Navigation will only see the `Home`, `Profile` and `Settings` screens, and when it returns `false`, React Navigation will see the `SignIn` and `SignUp` screens. This makes it impossible to navigate to the `Home`, `Profile` and `Settings` screens when the user is not signed in, and to `SignIn` and `SignUp` screens when the user is signed in.
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.
185156

186157
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.
187158

188-
The magic happens when the value returned by `useIsSignedin` changes. Let's say, initially `useIsSignedIn` returns `false`. This means, either `SignIn` or `SignUp` screens are shown. After the user signs in, the return value of `useIsSignedIn` will change to `true`. React Navigation will see that the `SignIn` and `SignUp` screens are no longer defined and so it will remove them. Then it'll show the `Home` screen automatically because that's the first screen defined when `useIsSignedIn` returns `true`.
189-
190-
The example shows stack navigator, but you can use the same approach with any navigator.
191-
192-
By conditionally defining different screens based on a variable, we can implement auth flow in a simple way that doesn't require additional logic to make sure that the correct screen is shown.
193-
194-
To do this, we need a couple of things:
195-
196-
<Tabs groupId="config" queryString="config">
197-
<TabItem value="static" label="Static" default>
198-
199-
1. Define two hooks: `useIsSignedIn` and `useIsSignedOut`, which return a boolean value indicating whether the user is signed in or not.
200-
2. Use the `useIsSignedIn` and `useIsSignedOut` along with the [`if`](static-configuration.md#if) property to define the screens that are available based on the condition.
201-
202-
</TabItem>
203-
204-
<TabItem value="dynamic" label="Dynamic">
205-
206-
1. Define two hooks: `useIsSignedIn` and `useIsSignedOut`, which return a boolean value indicating whether the user is signed in or not.
207-
2. Use the `useIsSignedIn` and `useIsSignedOut` along with conditional rendering to define the screens that are available based on the condition.
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`.
208160

209161
</TabItem>
210162
</Tabs>
211-
This tells React Navigation to show specific screens based on the signed in status. When the signed in status changes, React Navigation will automatically show the appropriate screen.
212163

213-
## Define the hooks
164+
## Add more screens
214165

215-
To implement the `useIsSignedIn` and `useIsSignedOut` hooks, we can start by creating a context to store the authentication state. Let's call it `SignInContext`:
216-
217-
```js
218-
import * as React from 'react';
219-
220-
const SignInContext = React.createContext();
221-
```
222-
223-
Then we can implement the `useIsSignedIn` and `useIsSignedOut` hooks as follows:
224-
225-
```js
226-
function useIsSignedIn() {
227-
const isSignedIn = React.useContext(SignInContext);
228-
return isSignedIn;
229-
}
230-
231-
function useIsSignedOut() {
232-
const isSignedIn = React.useContext(SignInContext);
233-
return !isSignedIn;
234-
}
235-
```
236-
237-
We'll discuss how to expose the context value later.
238-
239-
## Define our screens
240-
241-
In our navigator, we can conditionally define appropriate screens. For our case, let's say we have 3 screens:
166+
For our case, let's say we have 3 screens:
242167

243168
- `SplashScreen` - This will show a splash or loading screen when we're restoring the token.
244169
- `SignIn` - This is the screen we show if the user isn't signed in already (we couldn't find a token).
@@ -357,7 +282,7 @@ The main thing to notice is that we're conditionally defining screens based on t
357282
- `SignIn` screen is only defined if `userToken` is `null` (user is not signed in)
358283
- `Home` screen is only defined if `userToken` is non-null (user is signed in)
359284

360-
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` to define multiple screens:
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:
361286

362287
```js
363288
isSignedIn ? (
@@ -374,15 +299,15 @@ isSignedIn ? (
374299
);
375300
```
376301

377-
</TabItem>
378-
</Tabs>
379-
380302
:::tip
381303

382-
If you have both your login-related screens and rest of the screens in Stack navigators, 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.
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.
383305

384306
:::
385307

308+
</TabItem>
309+
</Tabs>
310+
386311
## Implement the logic for restoring the token
387312

388313
:::note
@@ -393,8 +318,8 @@ The following is just an example of how you might implement the logic for authen
393318

394319
From the previous snippet, we can see that we need 3 state variables:
395320

396-
- `isLoading` - We set this to `true` when we're trying to check if we already have a token saved in `SecureStore`
397-
- `isSignout` - We set this to `true` when user is signing out, otherwise set it to `false`
321+
- `isLoading` - We set this to `true` when we're trying to check if we already have a token saved in `SecureStore`.
322+
- `isSignout` - We set this to `true` when user is signing out, otherwise set it to `false`. This can be used to customize the animation when signing out.
398323
- `userToken` - The token for the user. If it's non-null, we assume the user is logged in, otherwise not.
399324

400325
So we need to:
@@ -590,11 +515,11 @@ const RootStack = createNativeStackNavigator({
590515
screen: HomeScreen,
591516
},
592517
SignIn: {
518+
if: useIsSignedOut,
593519
screen: SignInScreen,
594520
options: {
595521
title: 'Sign in',
596522
},
597-
if: useIsSignedOut,
598523
},
599524
},
600525
});
@@ -946,6 +871,10 @@ If you have a bunch of shared screens, you can also use [`navigationKey` with a
946871
</TabItem>
947872
</Tabs>
948873

874+
The examples above show stack navigator, but you can use the same approach with any navigator.
875+
876+
By specifying a condition for our screens, we can implement auth flow in a simple way that doesn't require additional logic to make sure that the correct screen is shown.
877+
949878
## Don't manually navigate when conditionally rendering screens
950879

951880
It's important to note that when using such a setup, you **don't manually navigate** to the `Home` screen by calling `navigation.navigate('Home')` or any other method. **React Navigation will automatically navigate to the correct screen** when `isSignedIn` changes - `Home` screen when `isSignedIn` becomes `true`, and to `SignIn` screen when `isSignedIn` becomes `false`. You'll get an error if you attempt to navigate manually.

0 commit comments

Comments
 (0)