Header title seems to not work as expected.
I already updated react-native and all other dependencies to their latest version and reviewed react-navigation documentation. Also I created a bug on github for this item.
Can you please take a look if I doing something wrong? I need to have header title set when i am using TabNavigation
const RootNavigator = createStackNavigator({
...publicScreens,
Private: {
screen: PrivateNavigator
}
}, publicScreensConfig);
const privateScreens = {
ContactList: {
screen: ContactList
},
Settings: {
screen: Settings
}
};
.....
export default createBottomTabNavigator( privateScreens, options );
import React, { Component } from 'react'
import { Text, View } from 'react-native'
import GlobalColors from '../../config/colors';
export default class Settings extends Component {
static navigationOptions = {
title: 'Settings',
headerStyle: {
backgroundColor: GlobalColors.grayDark,
},
headerTintColor: 'white',
headerTitleStyle: {
fontWeight: 'bold',
},
gesturesEnabled: false,
}
render() {
return (
<View>
<Text> Settigs </Text>
</View>
)
}
}
But I see empty header title in the header pane.
I want to see header text that come from navigation Options
Thanks to JinHoSo answer is here
const bottomTabNavigator = createBottomTabNavigator(...)
bottomTabNavigator.navigationOptions = ({navigation, screenProps}) => {
const childOptions = getActiveChildNavigationOptions(navigation, screenProps)
return {
title : childOptions.title,
headerLeft : childOptions.headerLeft,
headerRight: childOptions.headerRight,
}
}
Related
I just created a React Native app with Expo using expo init. Everything went fine. Then I went on and created a Home screen like so:
import React from 'react';
import { View, TextInput } from 'react-native';
export default class HomeScreen extends React.Component {
state = {
searchText: ""
}
render() {
return (
<View
style={{
flex: 1,
backgroundColor: 'white'
}}
>
<TextInput
placeholder="Search..."
value={this.state.searchText}
onChangeText={ (searchText) => this.setState({ searchText }) }
/>
</View>
);
}
}
I added it to my AppNavigator...
import { createAppContainer } from 'react-navigation';
import { createStackNavigator } from 'react-navigation-stack';
import HomeScreen from '../screens/HomeScreen';
const AppNavigator = createStackNavigator({
Home: HomeScreen
});
export default createAppContainer(AppNavigator);
...which I in turn added to App.js:
import React from 'react';
import { StyleSheet, View, StatusBar, Platform } from 'react-native';
import { AppLoading } from 'expo';
import AppNavigator from './navigation/AppNavigator';
export default class App extends React.Component {
state = {
isLoadingComplete: false
}
render() {
if (!this.state.isLoadingComplete && !this.props.skipLoadingScreen) {
return (
<AppLoading
startAsync={this._loadResourcesAsync}
onError={this._handleLoadingError}
onFinish={this._handleFinishLoading}
/>
);
}
return (
<View style={styles.container}>
{Platform.OS === 'ios' && <StatusBar barStyle="default" />}
<AppNavigator />
</View>
);
}
_loadResourcesAsync = async () => { };
_handleLoadingError = error => {
console.warn(error);
};
_handleFinishLoading = () => {
this.setState({ isLoadingComplete: true });
};
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#fff',
alignItems: 'center',
justifyContent: 'center',
},
});
Now, my problem is that my app looks like this:
As you can see, the horizontal margins are way too big, but I never set them to be like that. What am I doing wrong? I want the TextInput to stretch across the full screen.
Your HomeScreen Component will be as wide as its contents. You did not specify the width of the main View, therefore, it adjusted itself to be as wide the components inside. What you can do to resolve this issue is that you must provide width property in your Top level View's style.
And in order to get the Width of the screen, you can import Dimensions from react-native and use that like below:
const windowWidth = Dimensions.get('window').width;
and finally, you can assign the windowWidth to your view like so:
style={{flex:1, width: windowWidth, backgroundColor: 'white'}}
I am trying to get my button in the header to navigate to a gallery of images. When I press the button, I get "Cannot read property 'navigation' of undefined. Both of these files are in the same folder, which is "Profiles". Anybody know what this errors means and how to possibly fix it?
This is how I have the button set up in my headerRight.
//HomerSimpson.js
import React from "react";
import {
Button,
View,
Text,
StyleSheet,
Image,
List,
ListItem,
ImageBackground
} from "react-native";
import { withNavigation } from 'react-navigation';
import HomerGallery from "./Profiles/HomerGallery";
class HomerSimpson extends React.Component {
static navigationOptions = {
title: "Homer Simpson Profile",
headerStyle: {
backgroundColor: "#53b4e6"
},
headerTintColor: "#f6c945",
headerTitleStyle: {
fontWeight: "bold"
},
headerRight: (
<Button
onPress={() => this.props.navigation.navigate("HomerGallery")}
title="Gallery"
color="#f6c945"
/>
)
};
I made a separate component for the gallery itself and it's in the same folder as HomerSimpson.js.
//HomerGallery.js
import React from "react";
import {
Button,
View,
Text,
StyleSheet,
Image,
List,
ListItem,
ImageBackground
} from "react-native";
import ImageSlider from 'react-native-image-slider';
class HomerGallery extends React.Component {
static navigationOptions = {
title: "Homer's Gallery",
headerStyle: {
backgroundColor: "#53b4e6"
},
headerTintColor: "#f6c945",
headerTitleStyle: {
fontWeight: "bold"
},
headerRight: <Button onPress={() => alert("Bart loves to skateboard")} title="Facts" color="#f6c945" />
};
render() {
return (<ImageSlider images={[
'https://i.pinimg.com/474x/f1/36/ca/f136ca04817e60fa12f4a5680101ff8b.jpg',
'https://i.pinimg.com/474x/b1/da/e2/b1dae2fe6ca1620e5d1949a2dcd33a0c.jpg',
'https://i.pinimg.com/564x/7b/53/32/7b5332ef6a981b3c54e855495ea1c828.jpg',
'https://i.pinimg.com/564x/f4/71/79/f471798aeeae427474f544691d572970.jpg',
'https://i.pinimg.com/564x/32/3d/53/323d534f07de7d9ebeb58ede1f87d63e.jpg'
]}/>)
};
}
export default HomerGallery;
The route for the gallery is "HomerGallery". Here is how it's set up in my navigation file. It's imported, but I'll leave those il
import HomerGallery from "../../Profiles/HomerGallery";
import { createStackNavigator, createAppContainer } from "react-navigation";
const AppNavigator = createStackNavigator(
{
Login: Login,
Home: HomeScreen,
Details: DetailsScreen,
Bio: BioScreen,
EmployeeDirectory: EmployeeDirectory,
HomerSimpson: HomerSimpson,
BartSimpson: BartSimpson,
MargeSimpson: MargeSimpson,
LisaSimpson: LisaSimpson,
MaggieSimpson: MaggieSimpson,
SantasHelper: SantasHelper,
BarneyGumble: BarneyGumble,
MrBurns: MrBurns,
KentBrockman: KentBrockman,
RalphWiggum: RalphWiggum,
OttoMan: OttoMan,
Scratchy: Scratchy,
HomerGallery: HomerGallery,
BallBounce: BallBounce,
OverlayPage: OverlayPage,
Rankings: Rankings
},
{
initialRouteName: "HomerSimpson",
defaultNavigationOptions: {
headerStyle: '#f4511e',
},
headerTintColor: '#fff',
headerTitleStyle: {
fontWeight: 'bold',
},
},
);
export default createAppContainer(AppNavigator);
HomerSimpson.js
export default withNavigation(HomerSimpson)
This should pass all the necessary navigation props.
I think this is the offending line onPress={() => this.props.navigation.navigate("HomerGallery")}. The static object navigationOptions won't have access to this.props of the component.
You don't mention React Navigation, but I'm guessing that's what you're using. Here's an example from their docs that shows how you can access props by using a function instead of an object. Good luck!
static navigationOptions = ({ navigation }) => {
return {
title: navigation.getParam('otherParam', 'A Nested Details Screen'),
};
}
Update
Example applied to your code:
navigationOptions = ({ navigation }) => ({
title: "Homer Simpson Profile",
headerStyle: {
backgroundColor: "#53b4e6"
},
headerTintColor: "#f6c945",
headerTitleStyle: {
fontWeight: "bold"
},
headerRight: (
<Button
onPress={() => navigation.navigate("HomerGallery")}
title="Gallery"
color="#f6c945"
/>
)
});
I'm new to react-native. I use react-native-side-menu to create a drawer and I add a bottom on the left side to skip to another page. when I push the bottom, the error code appeared. However, if I put the bottom in the homepage, it works. Why if I put it in the drawer it will crash?
This is route stack
App.js
import React from 'react';
import { StyleSheet, Text, View } from 'react-native';
import { createStackNavigator, createAppContainer } from 'react-navigation';
import HomeScene from './homeScene';
import LoginScene from './loginScene';
import RegisterScene from './registerScene';
import TimetableScene from './timetable';
import ChatScene from './ChatScene';
import LeftMenu from './LeftMenu';
const SimpleApp = createStackNavigator({
Login: {
screen: LoginScene,
navigationOptions: {
headerTitle: 'Login',
}
},
Home: {
screen: HomeScene,
navigationOptions: {
header: null,
}
},
Register: {
screen: RegisterScene,
navigationOptions: {
headerTitle: 'Register',
}
},
Timetable: {
screen: TimetableScene,
navigationOptions:{
headerTitle: 'Timetable',
}
},
//The page I want to skip
Chat: {
screen: ChatScene,
navigationOptions:{
headerTitle: 'Chat',
}
}
LeftMenu:{
screen: LeftMenu
}
});
const AppContainer = createAppContainer(SimpleApp);
export default class App extends React.Component {
render() {
return <AppContainer />;
}
}
LeftScene.js
import React, { Component } from 'react';
import {
AppRegistry,
StyleSheet,
Text,
View,
TouchableOpacity,
SectionList
} from 'react-native';
export default class LeftMenu extends Component {
constructor(props) {
super(props);
this.selectSideMenu = this.selectSideMenu.bind(this);
}
selectSideMenu() {
this.props.onSelectMenuItem();
}
Chat = () => {
const { navigate } = this.props.navigation;
navigate('Chat');
}
render() {
return (
<View style={styles.container}>
//The bottom to skip to "Chat" page but will respond error
<TouchableOpacity
onPress={this.Chat}
style={styles.button}>
<Text
style={styles.btText}>Chat</Text>
</TouchableOpacity>
</View>
);
}
}
I think maybe the wrong code from the following code in LeftScene.js
Chat = () => {
const { navigate } = this.props.navigation;
navigate('Chat');
}
The this.props can only get the value from the parent component. The parent component of LeftMenu is homeScene, homeScene has no navigation so it doesn't work. And because of App.js is parent component of homeScene, so if I put the skip bottom in homeScene it can work. But I don't know how to figure out it...
homeScene.js
import React, { Component } from 'react';
import {
AppRegistry,
StyleSheet,
Text,
TextInput,
View,
TouchableOpacity,
Dimensions
} from 'react-native';
let { width, height } = Dimensions.get('window');
import SideMenu from 'react-native-side-menu'
import Menu from './LeftMenu'
export default class LeftSideMenu extends Component {
constructor(props) {
super(props);
this.state = {
isOpen: false,
}
this.SelectMenuItemCallBack = this.SelectMenuItemCallBack.bind(this);
}
SelectMenuItemCallBack() {
this.setState({
isOpen: !this.state.isOpen,
})
}
SelectToOpenLeftSideMenu() {
this.setState({
isOpen: true,
})
}
Chat = () => {
const { navigate } = this.props.navigation;
navigate('Chat');
}
render() {
const menu = <Menu onSelectMenuItem={this.SelectMenuItemCallBack} />;
return (
<SideMenu
menu={menu}
isOpen={this.state.isOpen}
onChange={(isOpen) => {
this.setState({
isOpen: isOpen,
})
}}
menuPosition={'left'}
openMenuOffset={0.75 * width}
edgeHitWidth={200}
>
<View
style={styles.top}>
//The bottom to open the drawer
<TouchableOpacity
onPress={() => this.SelectToOpenLeftSideMenu()}
style={styles.Fbutton} >
<Text
style={styles.btText}>F</Text>
</TouchableOpacity>
</View>
//The bottom to skip to "Chat" page and works
<View style={styles.container}>
<TouchableOpacity
onPress={this.Chat}
style={styles.button}>
<Text
style={styles.btText}>Chat</Text>
</TouchableOpacity>
</View>
</SideMenu>
);
}
}
I expect the bottom to skip to "Chat" page on the homeScene can be put in the drawer
You are facing this error because your LeftScene.js is not a part of your stack just add LeftScene.js in SimpleApp.
It will work.
Just change the code in homeScene.js
const menu = <Menu onSelectMenuItem={this.SelectMenuItemCallBack} />;
to the following
const menu = <Menu onSelectMenuItem={this.SelectMenuItemCallBack} navigation={this.props.navigation} />;
Consider the following example:
import { AppRegistry } from "react-native";
import React, { Component } from "react";
import {
createSwitchNavigator,
createStackNavigator,
createBottomTabNavigator
} from "react-navigation";
import Icon from "react-native-vector-icons/Ionicons";
import { withNavigation } from "react-navigation";
import {
View,
Text,
Platform,
TouchableNativeFeedback,
TouchableOpacity,
StyleSheet
} from "react-native";
const Touchable =
Platform.OS === "android" ? TouchableNativeFeedback : TouchableOpacity;
class ListComponent extends Component {
static navigationOptions = {
title: "List"
};
handleGo = () => {
this.props.navigation.navigate("Board");
};
render = () => {
//??? How to get myData ???
return (
<View>
<Text>HELLO LIST!!!!</Text>
<Touchable onPress={this.handleGo}>
<Text>GO TO BOARD</Text>
</Touchable>
<Text>{myData}</Text>
</View>
);
};
}
const List = withNavigation(ListComponent);
class BoardComponent extends Component {
static navigationOptions = {
title: "Board"
};
//??? How to get myData ???
render = () => {
return (
<View>
<Text>HELLO BOARD!!!!</Text>
<Text>{myData}</Text>
</View>
);
};
}
const Board = BoardComponent;
class PanelComponent extends Component {
static navigationOptions = {
title: "Panel"
};
//??? How to get myData ???
render = () => {
return (
<View>
<Text>HELLO PANEL!!!!</Text>
<Text>{myData}</Text>
</View>
);
};
}
const Panel = PanelComponent;
const Test0 = createStackNavigator(
{
List: {
screen: List
},
Board: {
screen: Board
}
},
{
navigationOptions: {
headerStyle: {
backgroundColor: "grey"
},
headerTintColor: "blue",
headerTitleStyle: {
fontWeight: "bold"
}
}
}
);
const Test1 = createStackNavigator(
{
Panel: {
screen: Panel
}
},
{
navigationOptions: {
headerStyle: {
backgroundColor: "grey"
},
headerTintColor: "blue",
headerTitleStyle: {
fontWeight: "bold"
}
}
}
);
const LoggedInNavigator = createBottomTabNavigator(
{
Test0: {
screen: Test0,
navigationOptions: {
tabBarIcon: ({ tintColor, focused }) => (
<Icon
name={"ios-list-box-outline"}
size={24}
color={"#cdcdcd"}
/>
)
}
},
Test1: {
screen: Test1,
navigationOptions: {
tabBarIcon: ({ tintColor, focused }) => (
<Icon
name={"ios-construct-outline"}
size={24}
color={"#cdcdcd"}
/>
)
}
}
},
{
tabBarOptions: {
showLabel: false,
activeTintColor: "white",
activeBackgroundColor: "blue",
style: {
backgroundColor: "grey"
}
},
animationEnabled: true,
swipeEnabled: true,
initialRouteName: "Test1"
}
);
export const createRootNavigator = () => {
let myData = getMyDataFromDB(); // <=== How can I pass myData down to Panel/Board/List
return createSwitchNavigator(
{
LoggedIn: {
screen: LoggedInNavigator
}
},
{
initialRouteName: "LoggedIn"
}
);
};
class App extends Component {
render = () => {
const Layout = createRootNavigator();
return <Layout />;
};
}
export default App;
AppRegistry.registerComponent("app", () => App);
How can I pass down myData through all the routes to the end components?
This is a skeleton of a much bigger application where I query for data on the root navigator (createRootNavigator) that must be served to some components down the navigation tree.
You could make a Higher Order Component or a wrapper component that handles the fetching of your data in componentDidMount and wrap all your routes with it
// HOC component example
import React from 'react';
const withMyData = (WrappedComponent) => {
class myEnchancedComponent extends React.Component {
state ={ myData: null }
componentDidMount() {
let myData = getMyDataFromDB();
// set the state after you get the data
this.setState({myData})
}
render() {
const {myData} = this.state;
return (
<WrappedComponent {...this.props} myData={myData}
/>
);
}
}
return myEnchancedComponent;
};
export default withMyData;
// example of how to use it
const List = withMyData(withNavigation(ListComponent));
The are other ways you can solve this too. You could use redux combined with redux-persist to store your data and make them available even offline.
He you can use redux for that, or another way is using local storage (react-native-local-storage), with this lib you can storage any data and in any moment or page you can access it.
following is my code:- posting full code
index.android.js
import React, { Component } from 'react';
import { AppRegistry, Text, StyleSheet, View, NetInfo, Alert, AsyncStorage } from 'react-native';
import Splash from './app/screens/Splash'
import { StackNavigator } from 'react-navigation'
import Login from './app/screens/Login'
import Register from './app/screens/Register'
import Check from './app/screens/Check'
import Qwerty from './app/screens/Qwerty'
import Home from './app/screens/Home'
var STORAGE_KEY = 'token';
var DEMO_TOKEN;
class Splashscreen extends React.Component {
static navigationOptions = {
header: null
};
async componentDidMount() {
const { navigate } = this.props.navigation;
var DEMO_TOKEN = await AsyncStorage.getItem(STORAGE_KEY);
if (DEMO_TOKEN === undefined) {
navigate("Login");
} else if (DEMO_TOKEN === null) {
navigate("Splash");
} else {
navigate("Temp");
}
};
render() {
const { navigate } = this.props.navigation;
return(
<View style={styles.wrapper}>
<View style={styles.titlewrapper}>
<Text style={styles.title}> Loding... </Text>
</View>
</View>
);
}
}
const Section = StackNavigator({
Root: {screen: Splashscreen},
Splash: { screen: Splash },
Login: { screen: Login },
Registerscreen: { screen: Register },
Temp: { screen: Check },
Qwerty:{screen: Qwerty},
Home:{screen: Home},
});
AppRegistry.registerComponent('shopcon', () => Section);
here i can navigate properly without any error Now,
This is my tab.js => Here i given three tabs (mainly working in first home.js)
import React, { PureComponent } from 'react';
import { Animated, StyleSheet,View } from 'react-native';
import { TabViewAnimated, TabBar } from 'react-native-tab-view';
import { StackNavigator } from 'react-navigation';
import Qwerty from './Qwerty';
import Home from './Home';
//import Login from './Login'
import type { NavigationState } from 'react-native-tab-view/types';
type Route = {
key: string,
title: string,
};
type State = NavigationState<Route>;
class Tab extends PureComponent<void, *, State> {
static navigationOptions = {
header: null
};
state: State = {
index: 0,
routes: [
{ key: '1', title: 'Home' },
{ key: '2', title: 'Shops' },
{ key: '3', title: 'Bookmark' },
],
};
_first: Object;
_second: Object;
_third: Object;
_handleIndexChange = index => {
this.setState({
index,
});
};
_renderLabel = props => ({ route, index }) => {
const inputRange = props.navigationState.routes.map((x, i) => i);
const outputRange = inputRange.map(
inputIndex => (inputIndex === index ? '#fff' : '#222')
);
const color = props.position.interpolate({
inputRange,
outputRange,
});
return (
<View>
<Animated.Text style={[styles.label, { color }]}>
{route.title}
</Animated.Text>
</View>
);
};
_renderHeader = props => {
return (
<TabBar
{...props}
pressColor="#999"
// onTabPress={this._handleTabItemPress}
renderLabel={this._renderLabel(props)}
indicatorStyle={styles.indicator}
tabStyle={styles.tab}
style={styles.tabbar}
/>
);
};
_renderScene = ({ route }) => {
switch (route.key) {
case '1':
return (
<Home
ref={el => (this._first = el)}
style={[styles.page, { backgroundColor: '#E3F4DD' }]}
/>
);
case '2':
return (
<Qwerty
ref={el => (this._second = el)}
style={[styles.page, { backgroundColor: '#E6BDC5' }]}
initialListSize={1}
/>
);
case '3':
return (
<Qwerty
ref={el => (this._third = el)}
style={[styles.page, { backgroundColor: '#EDD8B5' }]}
initialListSize={1}
/>
);
default:
return null;
}
};
render() {
return (
<TabViewAnimated
style={[styles.container, this.props.style]}
navigationState={this.state}
renderScene={this._renderScene}
renderHeader={this._renderHeader}
onIndexChange={this._handleIndexChange}
// onRequestChangeTab={this._handleIndexChange}
lazy
/>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
},
indicator: {
backgroundColor: '#fff',
},
label: {
fontSize: 18,
fontWeight: 'bold',
margin: 8,
},
tabbar: {
backgroundColor: '#ff6600',
},
tab: {
opacity: 1,
// width: 140,
},
page: {
backgroundColor: '#f9f9f9',
},
});
export default Tab;
This is Home.js => It is running well if i am using it directly but not running when using it in Tab.js
GoPressed(navigate){
navigate("Registerscreen");
}
render() {
const { navigate } = this.props.navigation;
contents = this.state.qwerty.data.map((item) => {
return (
<View>
{item.p1.shareproductid ? <TouchableHighlight onPress={() => this.GoPressed(navigate)} style={styles.button}>
<Text style={styles.buttonText}>
Go
</Text>
</TouchableHighlight> : null }
<Text>
{item.p1.content}
</Text>
</View>
);
});
return (
<ScrollView style={styles.container}>
{contents}
</ScrollView>
);
}
I am trying to navigate on Register screen after Go button pressed, But here it shows me error. I have used same navigation method before they works correctly but here it gives error. please show where i am going wrong?
How to navigate to any other(not these three screens of tab-view ) screen from tab-view?
I tried running Home.js in other way means not using in tab view then it is running and navigation also works but when i am calling Home.js in tab-view i.e in Tab.js then it showing error as in screenshot.
Seems like you're navigating to the wrong screen name.
This should do it.
GoPressed(navigate){
navigate("Registerscreen");
}
I honestly can't test out your code as it'll take too much time.
How about you check out this simple working example of what your looking for and match it with your code.
Go the Settings tab and then you can click on the button to navigate to the other Registerscreen which is not in the Tabs.
https://snack.expo.io/HJ5OqS5qZ