How to dynamically change the header title text in a react native app? - react-native

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’,
};
}

Related

passing array state to another class react native

I am new to React Native. I am making a lunch picker app for practice, and I wonder how to pass array of state to another class.
What I want to do is: show all data of array in child screen, so users can check the data by clicking on a button.
However, it seems like my code returns null array instead of getting original array. All codes are in one file, App.js
Home screen
class HomeScreen extends React.Component {
//initial
constructor(props) {
super(props);
this.state = {
isReady: false,
myMenu: '????',
menutext: '',
randomArray: ['a', 'b', 'c'],
};
}
render() {
return (
<View style={[styles.mainContainer]}>
<DetailsScreen menuListAA={this.state.randomArray} />
<Button
label="Show all menu"
onPress={() => {
/* 1. Navigate to the menu page route with params */
this.props.navigation.navigate('Details', {
itemId: 0,
otherParam: 'Show all menu',
});
}}
/>
</View>
Details screen
class DetailsScreen extends React.Component {
constructor(props) {
super(props);
this.state = {
}
}
static navigationOptions = {
title: 'All menu',
};
loadMenuList() {
const allMenuList = this.props.menuListAA;
return allMenuList.map((item, index) => <Text key={index}>{item}</Text>);
}
render() {
return (
<ScrollView>
<View style={styles.row}>{this.props.menuListAA}</View>
<Button
label="Go back"
onPress={() => this.props.navigation.goBack()}
/>
</ScrollView>
);
}
}
const RootStack = createStackNavigator(
{
Home: HomeScreen,
Details: DetailsScreen,
},
{
initialRouteName: 'Home',
}
);
const AppContainer = createAppContainer(RootStack);
export default class App extends React.Component {
render() {
return <AppContainer />;
}
}
Let me know if you need more information.
Please replace your code with one below :
Home screen
class HomeScreen extends React.Component {
//initial
constructor(props) {
super(props);
this.state = {
isReady: false,
myMenu: '????',
menutext: '',
randomArray: ['a', 'b', 'c'],
};
}
render() {
return (
<View style={[styles.mainContainer]}>
<DetailsScreen menuListAA={this.state.randomArray} />
<Button
label="Show all menu"
onPress={() => {
/* 1. Navigate to the menu page route with params */
this.props.navigation.navigate('Details', {
itemId: 0,
otherParam: 'Show all menu',
});
}}
/>
</View>
Doubts Detail : replace View with Text component
class DetailsScreen extends React.Component {
constructor(props) {
super(props);
this.state = {
}
}
static navigationOptions = {
title: 'All menu',
};
loadMenuList() {
const allMenuList = this.props.menuListAA;
return allMenuList.map((item, index) => <Text key={index}>{item}</Text>);
}
render() {
return (
<ScrollView>
//change View with Text as view cannot render characters and error says the same
<Text style={styles.row}>{this.props.menuListAA}</Text>
<Button
label="Go back"
onPress={() => this.props.navigation.goBack()}
/>
</ScrollView>
);
}
}
const RootStack = createStackNavigator(
{
Home: HomeScreen,
Details: DetailsScreen,
},
{
initialRouteName: 'Home',
}
);
const AppContainer = createAppContainer(RootStack);
export default class App extends React.Component {
render() {
return <AppContainer />;
}
}
you can pass data from parent to child by set props for child component like this: <Child data={this.state.yourData} /> //the props name is data,
then in child component in componentWillMount() you can access it:
ComponentWillMount(){
this.setState({childData: this.props.data}) // childData is an state of child component,rename it to your own`
}
in some case data maybe changed so we must to check this in componentDidUpdate() :
componentDidUpdate(){
if(this.props.data != this.state.childData){ //it is necessary because this function called many time's
this.setState({childData: this.props.data})
}
if you was in parent & want to give any data from child you must pass a function that returned data as like below:
<Child getData={(value)=> console.log(value)} />
then in your child you can do this:
this.props.getData(anyDataYouWantGetInParent)
hope this answer will be helpful,let me know any question
good luck.

Update value in StackNavigation custom header

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',
});

instance member is not accessible

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

React Navigation - Setting params without navigating to the scene

I want to add a 'reload' button to my header, which I'm doing by calling setParams. Problem is that this causes the TabNavigator to navigate to the tab at launch
export default class FeedScreen extends React.Component {
static navigationOptions = ({ navigation }) => {
const { params } = navigation.state;
if (params) {
return {
headerRight: <Icon.Button
color="black"
backgroundColor="transparent"
underlayColor="transparent"
name="reload"
onPress={ params.reload }
/>
};
}
}
constructor (props) {
super(props);
// We want to set attach a reload function to the navigation
this.props.navigation.setParams({
reload: this._reloadFeed.bind(this)
});
}
So is there a way setParams can not navigate to this scene, or is there a way to assign the function to this icon without calling setParams?
Have you tried setting onPress={ params.reload } to onPress={() => params.reload()}?
export default class FeedScreen extends React.Component {
static navigationOptions = ({ navigation }) => {
const { params } = navigation.state;
if (params) {
return {
headerRight: <Icon.Button
color="black"
backgroundColor="transparent"
underlayColor="transparent"
name="reload"
onPress={ () => params.reload() } < -----
/>
};
}
}
constructor (props) {
super(props);
// We want to set attach a reload function to the navigation
this.props.navigation.setParams({
reload: this._reloadFeed.bind(this)
});
}
You are probably looking for Navigation Actions, specifically Navigation Action that is called "setParams" (do not confuse with navigation.setParams()), which you dispatch this way: navigation.dispatch(myCreatedSetParamsAction)
I was able to work around this by calling a static function from the header, and just updating that static function to my reload function in the componentDidMount. It's hacky but works.
Function outside my component:
let _reloadFunction = () => {
// This exists because react navigation is a mess
}
Navigation options
static navigationOptions = {
headerRight: <Icon.Button
color="black"
backgroundColor="transparent"
underlayColor="transparent"
name="reload"
onPress={() => { _reloadFunction() }}
/>
}
In the component:
// Gonna update that reloadFunction so the header works
_reloadFunction = this._reloadFeed.bind(this);

React Native Navigation - Action using Component's State

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>)
}
}