What i'm trying to achieve from the Orders Screen is: If the user is not logged in he is directed to another screen. Which is also part of the stack. The transition is well but the header of origin screen (which in this case is orders.js) doesnt change
Orders.js
class Orders extends React.Component {
static navigationOptions = ({ navigation }) => {
return {
headerTitle: <TextHeader title={I18n.t('tabsLang.orders')} />,
headerTitleStyle: header.title,
headerLeft: <View />,
headerRight: <View />,
};
};
constructor(props) {
super(props);
this.state = {
orders: true,
isLoggedIn: false,
};
}
render() {
if (this.state.isLoggedIn) {
if (!this.state.orders) {
//Orders
return (
<View style={styles.container}>
<OrderItem />
</View>
);
} else {
//No Orders Screen
return <NoOrders />;
}
} else {
return <UserSplash/>;
}
}
}
export default Orders;
UserSplash.js
class Login extends React.Component {
static navigationOptions = ({ navigation }) => {
return {
header: null,
};
};
render() {...
}
}
There are two things I need to point out.
1. Double Header confusion
<Order>
Static navigationOptions = {
headerTitle: Something
}
render(){
if(state.isLoggedIn){
<View>
... Show orders or not
</View>
} else {
<UserSplash>
Static navigationOptions = {
header: null
}
</UserSplash>
}
}
</Order>
if you look at this, when you disable the header of the UserSplash, you are literally disabling the doubleheaders last one. If you don't disable it, you will see 2 headers on top of the view.
2. NavigationOptions
When you are setting the
navigationOptions
you are declaring it as Static if you are realized that. So it is not possible to change the parameters. I suggest you separate the UserSplash from the Order.js and just Navigate with your navigation.
Hope it helps. Good luck!
Related
my navigation initializeRoute screen is main.js
main.js have a onAuthStateCHange to detect a changes a current user
if current user is loggend main render component "ChatScreen"
else main render a compoment "LoginScreen"
the problem is chatScreen and LoginScreen have the same navigation header bar (main header bar)
I need the loginscreen does not have a header and the chatScreen does
i have tried use a
static navigationOptions = {header: null} in login and chat, but de header we can se is header of main.js
if i set header null on main the chatScreen is without header too
class App extends React.Component {
constructor() {
super();
this.unsubscriber = null;
this.state = {
user: null,
};
}
componentDidMount() {
this.unsubscriber = firebase.auth().onAuthStateChanged((user) => {
this.setState({ user });
});
}
render() {
if (!this.state.user) {
return <Login />;
}
return <Chat />;
}
}
The solution is the following in the main.js screen, you leave the navigation as you have it.
// main.js
static navigationOptions = ({ navigation }) => {
return { title: "", header: null
};
};
Then in the ChatScreen screen you personalize the header without depending on the react-navigation library, you do it in a personalized way.
// Chat.js
class Chat extends Component {
render() {
return (
<SafeAreaView>
{/*header*/}
<View style={{justifyContent: 'center', alignItems: 'center'}}>
<Text>Chat</Text>
</View>
{/*body*/}
<View>
</View>
</SafeAreaView>
);
}
}
export default Chat;
The child component Chat must receive the navigation properties
<Chat navigation={this.props.navigation} />
and in turn the chat children should be passed.
<SonChat navigation={this.props.navigation} />
I defined a custom view as a component for headerRight property in navigationOptions as bellow:
static navigationOptions = ({ navigation }) => {
return {
headerRight: navigation.getParam('headerRight', null),
};
};
and then in componentDidMount:
this.props.navigation.setParams({
headerRight: (<MessageDetailsHeader {...this.props}
title = {this.state.headerTitle}
subTitle = {this.state.headerSubTitle}
online = {this.state.online}
/>)
})
also i defined some state for updating values:
constructor(props) {
super(props);
this.state = {
headerTitle: null,
headerSubTitle: null,
headerOnline: false
};
}
Custom header view component defined as bellow:
export default class MessageDetailsHeader extends React.Component {
constructor(props) {
super(props);
this.state = {
title: this.props.title,
subTitle: this.props.subTitle,
online: this.props.online
};
}
componentWillReceiveProps(nextProps) {
this.setState({
title: nextProps.title,
subTitle: nextProps.subTitle,
online: nextProps.online,
})
}
render() {
return (
<View style={styles.headerContainer}>
<View style={styles.headerDetailsContainer}>
<Text style={styles.headerTitle}>{this.state.title}</Text>
<Text style={styles.headerSubTitle}>{this.state.subTitle}</Text>
</View>
<Avatar small rounded source={require('../images/no-profile.png')} activeOpacity={0.7} avatarStyle={this.state.online? styles.avatarOnline: styles.avatarOffline}/>
</View>
);
}
}
I need to call setState in screen and then update Custom View in navigation header, is this a right way?
Thanks in advance
Solved!
static navigationOptions = ({ navigation }) => {
const { params = {} } = navigation.state;
return {
headerRight: <MessageDetailsHeader
title={params.headerTitle}
subTitle={params.headerSubTitle}
online={params.headerOnline}
/>
};
};
and then called bellow code to set new value, easily!
this.props.navigation.setParams({
headerSubTitle: 'online',
});
How can I access class functions from inside stack navigator header? Is this possible?
What I'm trying to achieve is to call a function when I press the stack navigator header title.
class Dashboard extends React.Component {
static navigationOptions = ({ navigation }) => {
return {
headerTitle: (
<View style={header.addressView}>
<Text
style={header.titleAddress}
onPress={() => {
this._show().bind(this);
}}>
/>
</View>
),
};
};
_show(){
this.setState({ visibleModal: 1 })
}
constructor(props) {
super(props);
this.state = {
visibleModal: null,
};
}
render() {
...........
}
}
export default Dashboard;
class Dashboard extends React.Component {
static navigationOptions = ({ navigation }) => {
const showParams = navigation.getParam("show",()=>{});
//Access the params like this.
return {
headerTitle: (
<View style={header.addressView}>
<Text
style={header.titleAddress}
onPress={showParams}>
/>
</View>
),
};
};
_show(){
this.setState({ visibleModal: 1 })
}
//Too add this.
componentDidMount(){
this.props.navigation.setParams({show:()=>this._show()});
}
constructor(props) {
super(props);
this.state = {
visibleModal: null,
};
}
render() {
...........
}
}
export default Dashboard;
This is how you access the variables or states inside a class and make it available for the static navigationOptions function.
Reference
I have been struggling with something that sounds simple. I have been trying to get button when onpressed is called. Have tried several combinators but nothing works. Any ideas?
export default class JobScreen extends React.Component {
constructor(props) {
super(props);
}
static navigationOptions = ({navigation}) => ({
title: "Chat with"
});
onPressLearnMore(nav) {
// how do I update the title header
console.log("On Pressed" + nav)
}
render() {
const {navigate} = this.props.navigation;
return (
<View style={styles.container}>
<Button
onPress={() => {this.onPressLearnMore(navigate)}}
title="Learn More"
color="#841584"
/>
</View>
);
}
}
Since the navigationOptions has access to the navigation object, you can set some param on the current screen with this.props.navigation.setParam({ title: ‘some title’ }) and then access it in navigationOptions like this
static navigationOptions = ({ navigation }) => {
const { state: { params = {} } } = navigation;
return {
title: params.title || ‘default title’,
};
}
I've made a full-screen TextInput and would like to have an action performed when the Post button in the NavigationBar is pressed. However, because I have to make the method that the Button is calling in the onPress prop a static method, I don't have access to the state.
Here is my current code, and the state comes up undefined in the console.log.
import React, { Component } from 'react';
import { Button, ScrollView, TextInput, View } from 'react-native';
import styles from './styles';
export default class AddComment extends Component {
static navigationOptions = ({ navigation }) => {
return {
title: 'Add Comment',
headerRight: (
<Button
title='Post'
onPress={() => AddComment.postComment() }
/>
),
};
};
constructor(props) {
super(props);
this.state = {
post: 'Default Text',
}
}
static postComment() {
console.log('Here is the state: ', this.state);
}
render() {
return (
<View onLayout={(ev) => {
var fullHeight = ev.nativeEvent.layout.height - 80;
this.setState({ height: fullHeight, fullHeight: fullHeight });
}}>
<ScrollView keyboardDismissMode='interactive'>
<TextInput
multiline={true}
style={styles.input}
onChangeText={(text) => {
this.state.post = text;
}}
defaultValue={this.state.post}
autoFocus={true}
/>
</ScrollView>
</View>
);
}
}
Any ideas how to accomplish what I'm looking for?
I see you've found the solution. For future readers:
Nonameolsson posted how to achieve this on Github:
In componentDidMount set the method as a param.
componentDidMount () {
this.props.navigation.setParams({ postComment: this.postComment })
}
And use it in your navigationOptions:
static navigationOptions = ({ navigation }) => {
const { params } = navigation.state
return {
title: 'Add Comment',
headerRight: (
<Button
title='Post'
onPress={() => params.postComment()}
/>
),
};
};
Kinda like a hack but i use the global variable method where we assign this to a variable call foo. Works for me.
let foo;
class App extends Component {
static navigationOptions = ({ navigation }) => {
return {
title: 'Add Comment',
headerRight: (
<Button
title='Post'
onPress={() => foo.postComment() } <- Use foo instead of this
/>
),
};
};
componentWillMount() {
foo = this;
}
render() {
return (<div>Don't be a foo</div>)
}
}