I was making an app with react native and react-navigation. So what I did was I made a Login screen. Then I used react-navigation to create a native stack navigator and linked it to my Login screen. I successfully rendered the Login Screen but there seems to be some sort of default styling on the stack navigator(?). How do I remove or overwrite those styles so that the original styling of my screens come back? Images and Code below.
This is the stack navigator
import React from 'react';
import { NavigationContainer } from '#react-navigation/native';
import { createNativeStackNavigator } from '#react-navigation/native-stack';
import LoginScreen from '../screens/LoginScreen';
import SignUpScreen from '../screens/SignUpScreen';
const Stack = createNativeStackNavigator();
const AuthStack = () => {
return (
<NavigationContainer>
<Stack.Navigator initialRouteName="Login" screenOptions={{ header: () => null }}>
<Stack.Screen name="Login" component={LoginScreen} />
<Stack.Screen name="Signup" component={SignUpScreen} />
</Stack.Navigator>
</NavigationContainer>
);
};
export default AuthStack;
When I only render the LoginScreen it looks like this
When I use AuthStack it looks like this
Should have read the docs nicely it was there in the NativeStackNavigator options.
import React from 'react';
import { NavigationContainer } from '#react-navigation/native';
import { createNativeStackNavigator } from '#react-navigation/native-stack';
import LoginScreen from '../screens/LoginScreen';
import SignUpScreen from '../screens/SignUpScreen';
const Stack = createNativeStackNavigator();
const AuthStack = () => {
return (
<NavigationContainer>
<Stack.Navigator
initialRouteName="Login"
screenOptions={{
headerShown: false,
header: () => null,
contentStyle: { backgroundColor: 'white' },
}}
>
<Stack.Screen name="Login" component={LoginScreen} />
<Stack.Screen name="Signup" component={SignUpScreen} />
</Stack.Navigator>
</NavigationContainer>
);
};
export default AuthStack;
To do your own style do this
import { createStackNavigator } from "#react-navigation/stack";
import { NavigationContainer, DefaultTheme } from "#reactnavigation/native";
const MyTheme = {
...DefaultTheme,
colors: {
...DefaultTheme.colors,
background: Color.red,
},
};
Then do this
<NavigationContainer theme={MyTheme}>
<Stack.Navigator initialRouteName="startscreen" headerMode="none" >
</Stack.Navigator>
</NavigationContainer>
More information here (https://reactnavigation.org/docs/themes/)
Related
I get this error Error: "HomeScreen" is read-only.
I was compiling and executing this expo app via expo-start and then pressing "i" for the IOS simulator. Then it gives me the following error:
Error: "HomeScreen" is read-only.
This error is located at:
in App (created by withDevTools(App))
in withDevTools(App)
in RCTView (created by View)
in View (created by AppContainer)
in RCTView (created by View)
in View (created by AppContainer)
in AppContainer
in main(RootComponent)
at node_modules/react-native/Libraries/Core/ExceptionsManager.js:95:17 in reportException
at node_modules/react-native/Libraries/Core/ExceptionsManager.js:141:19 in handleException
at node_modules/react-native/Libraries/Core/setUpErrorHandling.js:24:39 in handleError
at node_modules/expo/build/errors/ExpoErrorManager.js:25:19 in errorHandler
at node_modules/expo/build/errors/ExpoErrorManager.js:30:24 in \<anonymous\>
at node_modules/#react-native/polyfills/error-guard.js:49:36 in ErrorUtils.reportFatalError
I just don't get it, what does it mean "Read-only"? I have full permission on everything.
I was expecting a "Login Screen" message in the top-left of the screen, respecting the notch and that stuff.
This is my code for app.js:
import { StatusBar } from "expo-status-bar";
import { StyleSheet, Text, View } from "react-native";
import { NavigationContainer } from '#react-navigation/native';
import { createNativeStackNavigator } from '#react-navigation/native-stack';
import LoginScreen from "./screens/LoginScreen";
import HomeScreen from "./screens/HomeScreen";
const Stack = createNativeStackNavigator();
export default function App() {
return (
<NavigationContainer>
<Stack.Navigator>
<Stack.Screen name="Home" component={HomeScreen={}} />
<Stack.Screen name="Login" component={LoginScreen={}} />
</Stack.Navigator>
</NavigationContainer>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: "#fff",
alignItems: "center",
justifyContent: "center",
},
});
This is for LoginScreen:
import { StyleSheet, Text, View } from 'react-native'
import React from 'react'
const LoginScreen = () => {
return (
<View>
<Text>LoginScreen</Text>
</View>
)
}
export default LoginScreen
const styles = StyleSheet.create({})
And this is for HomeScreen:
import { StyleSheet, Text, View } from 'react-native'
import React from 'react'
const HomeScreen = () => {
return (
<View>
<Text>HomeScreen</Text>
</View>
)
}
export default HomeScreen
const styles = StyleSheet.create({})
HomeScreen is a const which is read-only and can only be assigned a value once.
In your Stack.Screen you're setting the component prop to your custom components but assigning some value HomeScreen={}, same for LoginScreen
<Stack.Navigator>
<Stack.Screen name="Home" component={HomeScreen={}} />
<Stack.Screen name="Login" component={LoginScreen={}} />
</Stack.Navigator>
Instead use
<Stack.Navigator>
<Stack.Screen name="Home" component={HomeScreen} />
<Stack.Screen name="Login" component={LoginScreen} />
</Stack.Navigator>
I tried to create bottom Navigation,
Following this link : https://reactnavigation.org/docs/tab-based-navigation/#customizing-the-appearance
and here is my code :
import React from "react";
import { createBottomTabNavigator } from "#react-navigation/bottom-tabs";
import Ionicons from "react-native-vector-icons";
// Screens
import Home from "./Home";
import Settings from "./Settings";
const Tab = createBottomTabNavigator();
function MainContainer({ navigation }) {
return (
<Tab.Navigator
screenOptions={({ route }) => ({
tabBarIcon: ({ focused, color, size }) => {
let iconName;
if (route.name === "Home") {
iconName = focused
? "ios-information-circle"
: "ios-information-circle-outline";
} else if (route.name === "Settings") {
iconName = focused ? "ios-list-box" : "ios-list";
}
return <Ionicons name={iconName} size={size} color={color} />;
},
tabBarActiveTintColor: "tomato",
tabBarInactiveTintColor: "gray",
})}
>
<Tab.Screen name="Home" component={Home} />
<Tab.Screen name="Settings" component={Settings} />
</Tab.Navigator>
);
}
export default MainContainer;
But I got this error :
Error: Element type is invalid: expected a string (for built-in components) or a class/function (for composite components) but got: undefined. You likely forgot to export your component from the file it's defined in, or you might have mixed up default and named imports.
Check the render method of `TabBarIcon`.
I found out the mistake,
on the
import Ionicons from "react-native-vector-icons"; it should have been import Ionicons from "react-native-vector-icons/Ionicons"
Solutions:
You need wrap your <Tab.Navigator> into root navigation container
Example:
You need to first install dependency of #react-navigation/native
import {NavigationContainer} from '#react-navigation/native';
import {createStackNavigator} from '#react-navigation/stack';
import {createBottomTabNavigator} from '#react-navigation/bottom-tabs';
const Stack = createStackNavigator();
const Tab = createBottomTabNavigator();
const MainContainer = () => {
return (
<NavigationContainer>
<Tab.Navigator />
<Stack.Navigator />
...other your navigation
</NavigationContainer>
);
};
You can checkout react-navigaiton https://reactnavigation.org/docs/getting-started/
Just wrape your <Tab.Navigator> in <NavigationContainer>
import React from "react";
import { NavigationContainer } from '#react-navigation/native'
//Reset Imports
const Routes = () => {
return (
<NavigationContainer>
<Tab.Navigator>
</Tab.Navigator>
</NavigationContainer>
)
}
export default Routes
My app is currently set up as follows, and I want to show the Hub screen when the user presses on Study:
App.js:
import React, { Component } from 'react';
...
import { View } from 'react-native'
import { Provider } from 'react-redux'
import { createStore, applyMiddleware } from 'redux'
import rootReducer from './redux/reducers'
import thunk from 'redux-thunk'
const store = createStore(rootReducer, applyMiddleware(thunk))
...
export class App extends Component {
...
render() {
return (
<Provider store={store}>
<NavigationContainer>
<Stack.Navigator initialRouteName="Main">
<Stack.Screen name="Main" component={MainScreen} options={{ headerShown: false }}/>
</Stack.Navigator>
</NavigationContainer>
</Provider>
)
}
}
export default App
Main:
import React, { Component } from 'react'
import { View } from 'react-native'
import MaterialCommunityIcons from 'react-native-vector-icons/MaterialCommunityIcons'
import { connect } from 'react-redux'
import { bindActionCreators } from 'redux'
import { fetchUser, clearData } from '../redux/actions/index'
import ProfileScreen from './main/Profile'
import HomeScreen from './main/Home'
import StudyScreen from './main/Study'
import TestScreen from './main/Test'
import { createMaterialBottomTabNavigator } from '#react-navigation/material-bottom-tabs'
const Tab = createMaterialBottomTabNavigator();
// https://reactnavigation.org/docs/bottom-tab-navigator/
export class Main extends Component {
componentDidMount() {
this.props.clearData();
this.props.fetchUser();
}
render() {
...
return (
<Tab.Navigator initialRouteName="Home" activeColor="#f0edf6" barStyle={{ backgroundColor: '#694fad' }} shifting='true'>
<Tab.Screen name="Home" component={HomeScreen}
options={{
tabBarLabel: 'Home', tabBarColor: '#FF6347', tabBarIcon: ({ color, size }) => (
<MaterialCommunityIcons name="home" color={color} size={26}/>
),
}} />
<Tab.Screen name="Study" component={StudyScreen}
options={{
tabBarLabel: 'Study', tabBarColor: '#694FAD', tabBarIcon: ({ color, size }) => (
<MaterialCommunityIcons name="school" color={color} size={26}/>
),
}} />
<Tab.Screen name="Profile" component={ProfileScreen}
options={{
tabBarLabel: 'Profile', tabBarColor: '#1F65FF', tabBarIcon: ({ color, size }) => (
<MaterialCommunityIcons name="account" color={color} size={26}/>
),
}} />
<Tab.Screen name="Test" component={TestScreen}
options={{
tabBarLabel: 'Test', tabBarColor: '#3490AA', tabBarIcon: ({ color, size }) => (
<MaterialCommunityIcons name="history" color={color} size={26}/>
),
}} />
</Tab.Navigator>
)
}
}
const mapStateToProps = (store) => ({
currentUser: store.userState.currentUser
})
const mapDispatchProps = (dispatch) => bindActionCreators({fetchUser, clearData}, dispatch)
export default connect(mapStateToProps, mapDispatchProps)(Main);
Study:
import React, { Component } from 'react'
import { NavigationContainer } from '#react-navigation/native';
import { createStackNavigator } from '#react-navigation/stack';
const Stack = createStackNavigator();
import HubScreen from './studyWebviews/Hub'
export class Study extends Component {
render() {
return (
<NavigationContainer>
<Stack.Navigator initialRouteName="Hub">
<Stack.Screen name="Hub" component={HubScreen} options={{ headerShown: false }}/>
</Stack.Navigator>
</NavigationContainer>
);
}
}
Hub:
import React from 'react'
import { Text } from 'react-native'
export default function Hub() {
return (
<Text>Hub</Text>
)
}
Trying to load my app gives this error:
×
Error: Couldn't find a 'component', 'getComponent' or 'children' prop for the screen 'Study'. This can happen if you passed 'undefined'. You likely forgot to export your component from the file it's defined in, or mixed up default import and named import when importing.
How do I fix this? Please let me know if I need to clarify anything or make any changes for the sake of readability, thank you.
I believe you are importing the components incorrectly, as the message suggests: "...or mixed up default import and named import when importing."
Try export default class Study...
I am trying to create a simple Auth flow in my Expo application.
I've reacreated my project here so you can see what I am doing
Right now what happens in my app is I can register a user using Firebase authtentication, but can't navigate to the authenticated flows. Nothing happens after I click register, but I can see the user in firebase.
I have been reading the React Navigaion docs and tried implementing something similar to what they do for the Auth flow there, but have not had any success.
I think the issue has to do with how I am getting the token in App.js and my use of useEffect
App.js
import React, { useEffect } from 'react';
import * as eva from '#eva-design/eva';
import { Provider as AuthProvider } from './src/context/AuthContext';
import { createDrawerNavigator } from '#react-navigation/drawer';
import { createStackNavigator } from '#react-navigation/stack';
import { ApplicationProvider } from '#ui-kitten/components';
import { NavigationContainer } from '#react-navigation/native';
import LandingScreen from './src/screens/LandingScreen';
import RegisterScreen from './src/screens/RegisterScreen';
import LoginScreen from './src/screens/LoginScreen';
import HomeScreen from './src/screens/HomeScreen';
import DetailScreen from './src/screens/DetailScreen';
const Drawer = createDrawerNavigator();
const Stack = createStackNavigator();
/*eslint-disable */
export default function App() {
let token;
useEffect(() => {
// Fetch the token from storage then navigate to our appropriate place
const localSignin = async () => {
try {
token = await AsyncStorage.getItem('userToken');
} catch (e) {
// Restoring token failed
}
};
console.log(token);
localSignin();
}, []);
return (
<ApplicationProvider {...eva} theme={eva.light}>
<AuthProvider>
<NavigationContainer>
{token ? (
<>
<Drawer.Navigator initialRouteName="Home">
<Drawer.Screen name="Home" component={HomeScreen} />
<Drawer.Screen name="Details" component={DetailScreen} />
</Drawer.Navigator>
</>
) : (
<>
<Stack.Navigator>
<Stack.Screen name="Landing" component={LandingScreen} />
<Stack.Screen name="Register" component={RegisterScreen} />
<Stack.Screen name="Login" component={LoginScreen} />
</Stack.Navigator>
</>
)}
</NavigationContainer>
</AuthProvider>
</ApplicationProvider>
);
}
Should I be using my AuthContext here somewhere? I am very new to react development so I am sorry if this is somewhat unclear.
Your "token" is manipulated asynchronously, so it should be a state variable so your component may re-render when it got changed. To achieve that, you should replace your token declaration with
const [token, setToken] = React.useState(undefined);
After that, when you want to change your token, instead of reassigning to the token variable, call setToken with the desired value. Like this:
setToken(await AsyncStorage.getItem('userToken'));
The final code should look like this
import React, { useEffect } from 'react';
import * as eva from '#eva-design/eva';
import { Provider as AuthProvider } from './src/context/AuthContext';
import { createDrawerNavigator } from '#react-navigation/drawer';
import { createStackNavigator } from '#react-navigation/stack';
import { ApplicationProvider } from '#ui-kitten/components';
import { NavigationContainer } from '#react-navigation/native';
import LandingScreen from './src/screens/LandingScreen';
import RegisterScreen from './src/screens/RegisterScreen';
import LoginScreen from './src/screens/LoginScreen';
import HomeScreen from './src/screens/HomeScreen';
import DetailScreen from './src/screens/DetailScreen';
const Drawer = createDrawerNavigator();
const Stack = createStackNavigator();
/*eslint-disable */
export default function App() {
const [token, setToken] = React.useState(undefined);
useEffect(() => {
// Fetch the token from storage then navigate to our appropriate place
const localSignin = async () => {
try {
setToken(await AsyncStorage.getItem('userToken'));
} catch (e) {
// Restoring token failed
}
};
console.log(token);
localSignin();
}, []);
return (
<ApplicationProvider {...eva} theme={eva.light}>
<AuthProvider>
<NavigationContainer>
{token ? (
<>
<Drawer.Navigator initialRouteName="Home">
<Drawer.Screen name="Home" component={HomeScreen} />
<Drawer.Screen name="Details" component={DetailScreen} />
</Drawer.Navigator>
</>
) : (
<>
<Stack.Navigator>
<Stack.Screen name="Landing" component={LandingScreen} />
<Stack.Screen name="Register" component={RegisterScreen} />
<Stack.Screen name="Login" component={LoginScreen} />
</Stack.Navigator>
</>
)}
</NavigationContainer>
</AuthProvider>
</ApplicationProvider>
);
}
Link: snack
It is based on an example of the component: react-native-animated-tabbar.
But it seems that the problem is on the module #react-navigation/native, which on snack.expo does not seem to work properly, giving me the following error:
Device: (857:881) Attempted to assign to readonly property.
Evaluating module://#react-navigation/native.js
Evaluating module://App.tsx.js
Loading module://App.tsx
App.tsx:
import React from 'react';
import 'react-native-gesture-handler';
import { NavigationContainer } from '#react-navigation/native';
import { createStackNavigator } from '#react-navigation/stack';
import RootScreen from './screens/Root';
import BubbleScreen from './screens/Bubble';
import BubbleStyledScreen from './screens/BubbleStyled';
import BubbleRTLScreen from './screens/BubbleRTL';
const Stack = createStackNavigator();
export default function App() {
return (
<NavigationContainer>
<Stack.Navigator initialRouteName="Root" headerMode="none">
<Stack.Screen name="Root" component={RootScreen} />
<Stack.Screen name="Bubble" component={BubbleScreen} />
<Stack.Screen name="BubbleStyled" component={BubbleStyledScreen} />
<Stack.Screen name="BubbleRTL" component={BubbleRTLScreen} />
</Stack.Navigator>
</NavigationContainer>
);
}