Skip to content

Instantly share code, notes, and snippets.

@imranariffin
Last active August 7, 2021 08:51
Show Gist options
  • Save imranariffin/fcc649a4f30a1f70dc6f50d1873c4832 to your computer and use it in GitHub Desktop.
Save imranariffin/fcc649a4f30a1f70dc6f50d1873c4832 to your computer and use it in GitHub Desktop.
React Native Private/Public Screen Pattern - Wrap the `@react-navigation/stack` to be auth aware (Note: replace `.` in file names with `/` to make more sense)
import AScreen from 'screens/A'
import BScreen from 'screens/B'
import MainScreen from 'screens/Main'
import SignInScreen from 'screens/SignIn'
import SignUpScreen from 'screens/SignUp'
import SomeNestedScreen from 'screens/SomeNested'
import StackNavigator from './stack-navigator'
const Navigations = () => {
return (
<>
<StackNavigator.Navigator initialRouteName='SignIn'>
<StackNavigator.PublicScreen name='SignUp' component={SignUpScreen} />
<StackNavigator.PublicScreen name='SignIn' component={SignInScreen} />
</StackNavigator.Navigator>
<StackNavigator.Navigator initialRouteName='Main'>
<StackNavigator.PrivateScreen name='Main' component={MainScreen} />
<StackNavigator.PrivateScreen name='A' component={AScreen} />
<StackNavigator.PrivateScreen name='B' component={BScreen} />
<StackNavigator.Navigator initialRouteName='SomeNestedScreen'>
<StackNavigator.PrivateScreen name='SomeNestedScreen' component={SomeNestedScreen} />
</StackNavigator.Navigator>
</StackNavigator.Navigator>
</>
)
}
export default Navigations
import Stack from './stack'
const PublicScreen = ({ component, name }) => {
return <Stack.Screen name={name} component={component} />
}
export default PublicScreen
import PrivateScreen from './private-screen'
import PublicScreen from './public-screen'
import Stack from './stack'
export {
Navigator: Stack.Navigator,
PrivateScreen,
PublicScreen,
}
import Login from 'screens/Login'
import Stack from './stack'
const PrivateScreen = ({ isAuthenticated, component, name, navigateToLogin }) => {
if (!isAuthenticated) {
navigateToLogin()
return null
}
return <Stack.Screen name={name} component={component} />
}
export default PrivateScreen
import { connect } from 'react-redux'
import someAuthSelectors from 'src/authentication/selectors'
import PrivateScreen from './component'
const mapStateToProps = (state) => {
return {
// Let redux determine the state of authentication
isAuthenticated: someAuthSelectors.getIsAuthenticated(state),
}
}
const mapDispatchToProps = (dispatch, { navigation }) => {
return {
navigateToLogin: dispatch(navigation.navigate('Login')),
}
}
export default connect(
mapStateToProps,
mapDispatchToProps,
)(PrivateScreen)
import { createStackNavigator } from '@react-navigation/stack'
const Stack = createStackNavigator()
export default Stack
@hbina
Copy link

hbina commented Mar 30, 2020

Not sure if this is possible, but for PrivateScreen, why not this instead?

const PrivateScreen = ({ isAuthenticated, navigation, component, name }) => {
  if (!isAuthenticated) {
        navigation.navigate('Login');
  }
  return <Stack.Screen name={name} component={component} />
}

@imranariffin
Copy link
Author

imranariffin commented Mar 30, 2020

Not sure if this is possible, but for PrivateScreen, why not this instead?

const PrivateScreen = ({ isAuthenticated, navigation, component, name }) => {
  if (!isAuthenticated) {
        navigation.navigate('Login');
  }
  return <Stack.Screen name={name} component={component} />
}

Agreed, someone else has also pointed out this issue on Reddit.

const PrivateScreen = ({ isAuthenticated, navigation, component, name }) => {
  if (!isAuthenticated) {
      navigation.navigate('Login')
      return null
  }
  return <Stack.Screen name={name} component={component} />
}

I think your fix would work (plus a one-line amendment as above) but I will try to create a repo to test this when I have time.

Edit: Now the gist has been updated with a fix similar to @hbina's suggestion

@MeryemGh
Copy link

Hello , thanks for this code
but i keep receiving this error: Error: A navigator can only contain 'Screen' components as its direct children (found 'undefined' for the screen 'Login')
Is there anyway to resolve it ?

@hbina
Copy link

hbina commented Apr 26, 2021

Its been a while since I've use React but it seems like you passed an undefined value in <Login ...>. Share some code?

@MeryemGh
Copy link

MeryemGh commented May 4, 2021

Thanks hbina for responding i've used another method to solve the problem , !

@abhiburk
Copy link

abhiburk commented Aug 7, 2021

I keep get error Error: A navigator can only contain 'Screen' components as its direct children (found 'undefined' for the screen 'Login')

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment