Hello I 'm trying to bind a function in my Navigator Right Button,
But It gives error.
This is my code:
import React, { Component } from 'react';
import Icon from 'react-native-vector-icons/FontAwesome';
import Modal from 'react-native-modalbox';
import { StackNavigator } from 'react-navigation';
import {
Text,
View,
Alert,
StyleSheet,
TextInput,
Button,
TouchableHighlight
} from 'react-native';
import NewsTab from './tabs/news-tab';
import CustomTabBar from './tabs/custom-tab-bar';
export default class MainPage extends Component {
constructor(props) {
super(props);
}
alertMe(){
Alert.alert("sss");
}
static navigationOptions = {
title: 'Anasayfa',
headerRight:
(<TouchableHighlight onPress={this.alertMe.bind(this)} >
<Text>asd</Text>
</TouchableHighlight>)
};
render() {
return(
<View>
</View>
);
}
}
And Get error like this:
undefined is not an object (evaluating 'this.alertMe.bind')
When I use this method in render function it is working great but in NavigatonOption I cant get handled it. what can I do for this problem.
You should use this in you navigator function
static navigationOptions = ({ navigation }) => {
const { params = {} } = navigation.state;
return {
title: '[ Admin ]',
headerTitleStyle :{color:'#fff'},
headerStyle: {backgroundColor:'#3c3c3c'},
headerRight: <Icon style={{ marginLeft:15,color:'#fff' }} name={'bars'} size={25} onPress={() => params.handleSave()} />
};
};
use the componentwillmount so that it can represent where you are calling function .
componentDidMount() {
this.props.navigation.setParams({ handleSave: this._saveDetails });
}
and then you can write your logic in the function
_saveDetails() {
**write you logic here for **
}
**no need to bind function if you are using this **
May be same as above ...
class LoginScreen extends React.Component {
static navigationOptions = {
header: ({ state }) => ({
right: <Button title={"Save"} onPress={state.params.showAlert} />
})
};
showAlert() {
Alert.alert('No Internet',
'Check internet connection',
[
{ text: 'OK', onPress: () => console.log('OK Pressed') },
],
{ cancelable: false }
)
}
componentDidMount() {
this.props.navigation.setParams({ showAlert: this.showAlert });
}
render() {
return (
<View />
);
}
}
react-navigation v5 version would be:
export const ClassDetail = ({ navigation }) => {
const handleOnTouchMoreButton = () => {
// ...
};
useLayoutEffect(() => {
navigation.setOptions({
headerRight: () => (
<TouchableOpacity onPress={handleOnTouchMoreButton}>
<Icon name="more" />
</TouchableOpacity>
),
});
}, [navigation]);
return (
// ...
)
}
This is for navigation v4. You need to modify navigationoptions outside of the functional component. Your button event needs to pass a param via navigation.
pageName['navigationOptions'] = props => ({
headerRight: ()=>
<TouchableOpacity onPress={() => props.navigation.navigate("pageRoute",
{"openAddPopover": true}) } ><Text>+</Text></TouchableOpacity> })
and then in your functional component, you can use that param to do something like this:
useLayoutEffect(() => {
doSomethingWithYourNewParamter(navigation.getParam("openAddPopover"))
}, [navigation])
Related
I have a problem when i try to navigation.navigate called RegisterPage but before that i try to typing anycharacter in field email and after that i click register button and back again, but the field is not empty
LoginContainer.js
import React, { Component, Fragment } from 'react';
import LoginComponent from '../../modules/LoginComponent/component/LoginComponent';
import axios from 'axios';
import { Toast } from '#ant-design/react-native';
class LoginContainer extends Component {
static navigationOptions = {
header: null,
}
constructor(props) {
super(props);
this.state = {
post : [],
email : '',
password : '' ,
showPassword: true,
}
}
onValueChange = (text, name) => {
this.setState({
[name] : text
});
}
getPostAPI = () => {
axios.get('http://10.2.62.212:3000/dataadmin')
.then((res) => {
this.setState ({
post : res.data,
})
})
.catch((err) => {
})
}
showPassword = () => {
const showPassword = !this.state.showPassword
this.setState({ showPassword });
}
onLoginPress = (event) => {
event.preventDefault();
const { post } = this.state;
if(!this.state.email.trim()) {
Toast.fail('Invalid Email', 1, undefined, false)
} else
if(!this.state.password.trim()) {
Toast.fail('Invalid Password', 1, undefined, false)
} else
if (post.find(e => `${e.email}${e.password}` === `${this.state.email}${this.state.password}` )) {
this.props.navigation.navigate('Dashboard');
} else
if (post.find(e => `${e.email}${e.password}` !== `${this.state.email}${this.state.password}` )) {
Toast.fail('Invalid Email or Password', 1, undefined, false)
}
}
onRegistPress = () => {
this.props.navigation.navigate('Register')
}
componentDidMount() {
this.getPostAPI();
}
render() {
return (
<Fragment>
<LoginComponent
navigation = {this.props.navigation}
change = {this.props.change}
onValueChange={this.onValueChange}
showPassword={this.showPassword}
onLoginPress={this.onLoginPress}
showPassword={this.state.showPassword}
onRegistPress = {this.onRegistPress}
/>
</Fragment>
);
}
}
export default LoginContainer;
LoginComponent.js
import React from 'react';
import { View, Text, TextInput, TouchableOpacity } from 'react-native';
import PropTypes from 'prop-types';
import { Button, Icon, Provider } from '#ant-design/react-native';
import styles from '../../../../assets/styles/default.style'
class LoginComponent extends React.Component {
static navigationOptions = {
header: null,
}
render() {
return (
<Provider >
<View style={styles.containerLogin}>
<View style={styles.parentViewStyleLogin}>
<Text style={styles.textHeaderStyle}> Merchant APP </Text>
<Text style={styles.textStyle}>Email</Text>
<View style={styles.inputContainer}>
<Icon style = {styles.styleIcon} name={"user"} color='black'/>
<TextInput
style={styles.textboxfield}
underlineColorAndroid='transparent'
onChangeText={(text) => this.props.onValueChange(text, 'email')}
placeholder = {'Input your email here'}
placeholderTextColor={'rgba(221,221,221,1)'}
/>
</View>
<Text style={[styles.textStyle, {marginTop: 20}] }> Password </Text>
<View style={styles.inputContainer}>
<Icon style = {styles.styleIcon} name={"key"} color='black'/>
<TextInput
style={styles.textboxfield}
secureTextEntry={this.props.showPassword}
underlineColorAndroid='transparent'
onChangeText={(text) => this.props.onValueChange(text, 'password')}
returnKeyType={'done'}
placeholder = {'Input your password here'}
placeholderTextColor={'rgba(221,221,221,1)'}
/>
</View>
<TouchableOpacity >
<Button style={[styles.buttonTextStyle, { borderRadius : 30 }]} onPress = {this.props.onLoginPress} >Login</Button>
</TouchableOpacity>
<TouchableOpacity onPress = {() => this.props.onRegistPress()} >
<Text style={styles.textDefault} >Dont have account ? Register</Text>
</TouchableOpacity>
</View>
</View>
</Provider>
);
}
}
export default LoginComponent
navigation
import { createStackNavigator } from 'react-navigation-stack';
import { createAppContainer } from 'react-navigation';
import LoginContainer from '../../app/LoginContainer/LoginContainer';
import DashboardContainer from '../../app/DashboardContainer/DashboardContainer';
import NotificationContainer from '../../app/NotificationContainer/NotificationContainer';
import TransactionContainer from '../../app/TransactionContainer/TransactionContainer'
import RegisterContainer from '../../app/RegisterContainer/RegisterContainer'
import DetailContainer from '../../app/DetailContainer/DetailContainer';
const AppNavigator = createStackNavigator(
{
Login: { screen: LoginContainer },
Dashboard: { screen: DashboardContainer },
Notification: { screen: NotificationContainer },
Transaction : { screen: TransactionContainer },
Register : { screen : RegisterContainer },
Detail : { screen : DetailContainer }
},
);
export default createAppContainer(AppNavigator);
this my ui
look after i try to type anycharacter and then directly click signup , and then click sigin again , and the field is not empty. i dont know how to fix it
there are 2 ways you can achieve this :
While you click on register in the DOnt have account text , then before navigation.navigate you can set the state of email to '' , like
onRegisterClick = () =>{
this.setSTate({email:''});//first this
this.props.navigation.navigate('Register');//then this
}
You can go back to the login page again by this.props.navigation.push('Login') rahther than navigation.navigate coz what navigate does is it calls the page from existing stack ,and push creates a new stack so values will be reset , so email will be null
I don't want the navigation to change, just the icon. So I can intercept the button press and prevent navigation, but I haven't been able to figure out how to change the icon. I want to change if from a Play to a Pause.
The nav option that displays the icon:
this.props={isPlaying:false}
const PlayStack = createStackNavigator({
Play: PlayScreen,
});
PlayStack.navigationOptions = {
tabBarLabel: ' ',
tabBarIcon: () => (
<PlayTabBarIcon
name={Platform.OS === 'ios' ? (this.props.isPlaying ? 'ios-pause' : 'ios-play') : (this.props.isPlaying ? 'md-pause' : 'md-play') }
/>
),
tabBarOnPress: (tab, jumpToIndex) => {
this.props.isPlaying = !this.props.isPlaying;
console.log(tab);
}
};
And here's the PlayTabBarIcon class
import React from 'react';
import { Icon } from 'expo';
import { Platform } from 'react-native';
import Colors from '../constants/Colors';
export default class PlayTabBarIcon extends React.Component {
render() {
return (
<Icon.Ionicons
name={this.props.name}
size={46}
style={{ marginBottom: -3 }}
color={Colors.green}
/>
);
}
}
I wasn't able to figure out how to do this from the tabBarOnPress method of the navigationOption, but I did manage to get the functionality I needed inside the component. The component creation changes to:
const PlayStack = createStackNavigator({
Play: PlayScreen,
});
PlayStack.navigationOptions = {
tabBarLabel: ' ',
tabBarIcon: () => (
<PlayTabBarIcon
playName={Platform.OS === 'ios' ? 'ios-play' : 'md-play' }
pauseName={Platform.OS === 'ios' ? 'ios-pause' : 'md-pause' }
isPlaying={false}
/>
)
};
and the component changes to:
import React from 'react';
import { Icon } from 'expo';
import { Platform } from 'react-native';
import Colors from '../constants/Colors';
export default class PlayTabBarIcon extends React.Component {
render() {
return (
<Icon.Ionicons
name={this.state.isPlaying ? this.props.pauseName : this.props.playName}
size={46}
style={{ marginBottom: -3 }}
color={Colors.green}
onPress={ () => this.setState({isPlaying: !this.state.isPlaying}) }
/>
);
}
componentDidUpdate(prevProps, prevState, snapshot) {
if (this.state.isPlaying != prevState.isPlaying) {
console.log('play state changed')
}
}
constructor(props) {
super(props);
this.state = {isPlaying: props.isPlaying };
}
}
tabBarIcon: ({focused }) => (
<Image resizeMode='cover' source={focused ? "Image URL Here": ""Image URL Here""} />
)
focused parameter return Boolean value(This focused parameter check you are focused to the tab or not. if you're focused it's return true if you're not focused it's return false)
I am an Android Application Developer. I have started working on React-Native. I am unable to find a way to show expandable list inside navigation drawer. Suggest a library if this functionality can be done in that. navigationOptions does not have a way to provide a list (refer code below).
I want to show expandable view like item 4
My Code is :-
import {DrawerNavigator} from 'react-navigation';
import React, {Component} from 'react';
import {
Platform,
StyleSheet,
Text,
Image,
View,
TouchableHighlight
} from 'react-native';
import Screen1 from './screen/Screen1'
import Screen2 from './screen/Screen2'
const util = require('util');
class MyHomeScreen extends React.Component {
constructor(props) {
super(props);
this.state = {
headertitle: 'ffffff'
};
}
componentWillReceiveProps(nextProps) {
navigationOptions = {
title: this.nextProps.headertitle
};
}
static navigationOptions = {
drawerLabel: 'Home',
drawerIcon: ({tintColor}) => (
<Image
source={require('./images/document.png')}
style={[
styles.icon, {
tintColor: tintColor
}
]}/>),
title: 'NIIT'
};
render() {
return (<Screen1/>);
}
}
class MyNotificationsScreen extends React.Component {
static navigationOptions = {
drawerLabel: 'Notifications',
drawerIcon: ({tintColor}) => (<Image source={require('./images/smartphone.png')} style={[styles.icon]}/>),
title: 'Gnome'
};
render() {
return (<Screen2/>);
}
}
const styles = StyleSheet.create({
icon: {
width: 24,
height: 24
}
});
const DrawerScreen = DrawerNavigator({
Screen1: {
screen: MyHomeScreen
},
Screen2: {
screen: MyNotificationsScreen
}
}, {headerMode: 'none'})
export default DrawerScreen;
I think this is a single class, simple implementation of what the OP is asking for. It uses react-navigation v5. It's a standalone component that is configured via the ExpandableDrawerProps (title is the name of parent drawer, i.e. what contains the subdrawers and has no navigation, and choices is a map of label name to navigation screen component names.) It is written in TypeScript (both of these are .tsx files), so if you're not using TypeScript, just strip out the typing.
import {
DrawerContentComponentProps,
DrawerContentScrollView,
DrawerItem,
} from '#react-navigation/drawer';
import React from 'react';
import { Text, View } from 'react-native';
import { TouchableOpacity } from 'react-native-gesture-handler';
import styles from './styles';
export type ExpandableDrawerProps = DrawerContentComponentProps & {
title: string;
choices: Map<string, string>;
};
export default class ExpandableDrawer extends React.Component<
ExpandableDrawerProps,
{
isExpanded: boolean;
}
> {
constructor(props: ExpandableDrawerProps, state: { isExpanded: boolean }) {
super(props);
this.state = state;
}
onPress = (): void => {
this.setState(() => {
return {
isExpanded: !this.state.isExpanded,
};
});
};
render = (): JSX.Element => {
return (
<View style={styles.container}>
<TouchableOpacity
activeOpacity={0.8}
onPress={this.onPress}
style={styles.heading}
>
<Text style={styles.expander}>{this.props.title}</Text>
</TouchableOpacity>
{this.state.isExpanded ? (
<DrawerContentScrollView>
<View style={styles.expandedItem}>
{[...this.props.choices.keys()].map(
(label: string): JSX.Element | null => {
const screen = this.props.choices.get(label);
if (screen != undefined) {
return (
<DrawerItem
key={label}
label={label}
onPress={(): void => {
this.props.navigation.navigate(screen);
}}
/>
);
} else {
return null;
}
}
)}
</View>
</DrawerContentScrollView>
) : null}
</View>
);
};
}
You can drop that code in a file, make a simple styles file or remove them from that code, and then you're able to use <ExpandableDrawerMenu {...expandable} />
in your normal drawer navigation.
Here's how I used it in a normal navigation drawer.
const DrawerContent = (props: DrawerContentComponentProps): JSX.Element => {
const c = new Map<string, string>();
c.set('SubItem 1', 'SubItem1');
c.set('SubItem 2', 'SubItem2');
const expandable: ExpandableDrawerProps = {
title: 'Expandable Drawer',
choices: c,
navigation: props.navigation,
state: props.state,
descriptors: props.descriptors,
progress: props.progress,
};
return (
<DrawerContentScrollView {...props}>
<View style={styles.drawerContent}>
<Drawer.Section style={styles.drawerSection}>
<DrawerItem
label="Item 1"
onPress={(): void => {
props.navigation.navigate('Item1');
}}
/>
<ExpandableDrawerMenu {...expandable} />
<DrawerItem>
label="Item 2"
onPress={(): void => {
props.navigation.navigate('Item2');
}}
/>
<DrawerItem
label="Item 3"
onPress={(): void => {
props.navigation.navigate('Item3');
}}
/>
</Drawer.Section>
</View>
</DrawerContentScrollView>
);
};
export default class Navigator extends Component {
render = (): JSX.Element => {
const Drawer = createDrawerNavigator();
return (
<NavigationContainer>
<Drawer.Navigator
drawerContent={(props: DrawerContentComponentProps): JSX.Element =>
DrawerContent(props)
}
initialRouteName="Item1"
>
<Drawer.Screen name="Item1" component={Item1Screen} />
<Drawer.Screen name="SubItem1" component={SubItem1Screen} />
<Drawer.Screen name="SubItem2" component={SubItem2Screen} />
<Drawer.Screen name="Item2" component={Item2Screen} />
<Drawer.Screen name="Item3" component={Item3Screen} />
</Drawer.Navigator>
</NavigationContainer>
);
};
}
react-navigation does not, at this time, support a collapsible menu in the drawer navigator.
You can, however, implement your own, by supplying your own contentComponent to the navigator:
const DrawerScreen = DrawerNavigator({
Screen1: {
screen: MyHomeScreen
},
Screen2: {
screen: MyNotificationsScreen
}
}, {
headerMode: 'none',
contentComponent: MyDrawer
})
const MyDrawer = (props) => ...
See the documentation for more information.
You can use something like react-native-collapsible to achieve the effect of the collapsible menu itself.
I have developed a solution for this problem. My code uses "#react-navigation/drawer": "^5.1.1" and "#react-navigation/native": "^5.0.9".
Gihub link - https://github.com/gyanani-harish/ReactNative-ExpandableDrawerMenu
Im doing this inside the react native platform using expo.
I want to display the list of items ( ListItems.js) All_Employees_screen.js . These items are being rendered via a functional component, I want to have a onRowPress() handler to so that upon clicking it i can navigate it to another view, but I dont know how to do it on react-navigation ?
Or since the new functional component can be a class component( this would be better ) how can i access the navigation thing inside it ?
AllProperties.js
import _ from 'lodash';
import React, {
Component
} from 'react';
import {
Button,
ListView,
ScrollView
} from 'react-native';
import ListItem from './ListItem';
import { connect } from 'react-redux';
import { propertiesFetch } from '../../actions';
// import { FormLabel, FormInput } from 'react-native-elements'
class AllPropertiesScreen extends React.Component {
componentWillMount(){
this.props.propertiesFetch();
this.createDataSource(this.props);
}
// we do this componentWillMount & componentWillReceiveProps (nextProps) thing twice, coz once the component is
// loaded it loads all teh values but when user hits another view like Create property, The Property data still exists
// in the global state object,
// we could move all the dc dataSource code into componentWillReceiveProps but its actually gonna benefit us
// if we make sure that we try to build our data source both when the component first loads up
// & when second time after we go back and forth other compoennts.
componentWillReceiveProps(nextProps){
// nextProps are the next set of props that this component will be rendered with
// this.props is still the old set of props
this.createDataSource(nextProps);
}
createDataSource({ properties }){
const ds = new ListView.DataSource({
rowHasChanged: (r1, r2) => r1 !== r2
});
this.dataSource = ds.cloneWithRows(properties);
}
static navigationOptions = ({ navigation }) => {
const {state, setParams} = navigation;
return {
title: 'All Emplooyee',
headerRight: (
<Button
title='Add'
// onPress={() => setParams({ mode: isInfo ? 'none' : 'info'})}
onPress={() => navigation.navigate('createProperty')
}
/>
),
};
};
goBack(){
console.log('65 - go Back clicked');
}
renderRow(property){
// console.log('67-AllPropertiesScreen =', property);
return <ListItem property={property}
onPress={() => { console.log('65 - go Back clicked') }}
/>;
}
render() {
console.log('72-AllPropertiesScreen this.props', this.props );
return(
<ListView
enableEmptySections
dataSource={this.dataSource}
renderRow={this.renderRow}
/>
);
}
}
const mapStateToProps = state => {
console.log('83 - AllPropertiesScreen state. properties', state );
const properties = _.map(state.properties, (val, uid ) => {
return { ...val, uid }; // { shift: 'Monday'}
});
return { properties };
};
export default connect(mapStateToProps, {propertiesFetch}) (AllPropertiesScreen);
ListItem.js
import React, { Component } from 'react';
import { Text, TouchableWithoutFeedback, View } from 'react-native';
class ListItem extends Component {
// onRowPress(){
// Actions.employeeEdit({ employee: this.props.employee });
// }
render(){
const { agent_name, cell, address } = this.props.property;
console.log('14- ListItem ', this.props);
return (
<View>
<CardSection>
<Text style={styles.titleStyle}>
name
</Text>
<Text style={styles.titleStyle}>
cell
</Text>
<Text style={styles.titleStyle}>
address
</Text>
</CardSection>
</View>
);
}
}
const styles = {
titleStyle: {
fontSize: 18,
paddingLeft: 15
}
}
export default ListItem;
//
main.js ( this is where I have all the navigation paths hookedup.
class App extends React.Component {
render() {
const MainNavigator = TabNavigator({
// auth: { screen : AuthScreen },
// review: { screen: ReviewScreen },
// signup: { screen : SignupScreen },
followup: { screen: FollowupScreen }, welcome: { screen : WelcomeScreen },
auth: { screen : AuthScreen },
signup: { screen : SignupScreen },
main: {
screen: TabNavigator ({
followup: { screen: FollowupScreen },
map: { screen: MapScreen },
deck: { screen: DeckScreen },
settings : {
screen: StackNavigator ({
settings: { screen: SettingsScreen },
// settings: { screen: SettingsScreen },
UserProfile: { screen: UserProfileScreen },
HelpSupport: { screen: HelpSupportScreen },
Notifications: { screen: NotificationsScreen },
Signout: { screen: SignoutScreen } // not working, Navigation object not accessible inside the component
}) //screen: StackNavigator ({
},
followup : {
screen: StackNavigator ({
followup: { screen: FollowupScreen },
allProperties: { screen: AllPropertiesScreen },
createProperty: { screen: PropertyCreateScreen },
Red: { screen: RedPriorityScreen }, // not working, Navigation object not accessible inside the component
GreyPriority: { screen: GreyPriorityScreen },
}) //screen: StackNavigator ({
},
draw: {
screen: DrawerNavigator ({
drawin: { screen: DrawScreen },
}) //screen: StackNavigator ({
}
}) //screen: TabNavigator
}
}, {
navigationOptions: {
tabBarVisible: false
},
lazy: true
});
return (
<Provider store={store}>
<View style={styles.container}>
<MainNavigator />
</View>
</Provider>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#fff',
// alignItems: 'center',
justifyContent: 'center',
},
});
Expo.registerRootComponent(App);
Solution suggested by #Matt but as soon as I put the navigation={this.props.navigation} it complains. undefined is not an object ( evaluating this.props.navigation )
renderRow(property){
return (
<ListItem
property={property}
navigation={this.props.navigation}
onPress={() => {
console.log( '70-on Press inside renderRow ');
}}/>
);
}
If the component is not a screen you have to import the navigation.
Try this:
import React from 'react';
import { Button } 'react-native';
import { withNavigation } from 'react-navigation';
class MyBackButton extends React.Component {
render() {
return <Button title="Back" onPress={() => { this.props.navigation.goBack() }} />;
}
}
// withNavigation returns a component that wraps MyBackButton and passes in the
// navigation prop
export default withNavigation(MyBackButton);
For more info check out
https://reactnavigation.org/docs/connecting-navigation-prop.html
This answer was written for old version of react-navigation V1
I had the same exact problem, and I found out that this.props.navigation is injected only in components that are registered as screen in StackNavigator or TabbNavigator.
but in general you can use navigate from NavigationActions class (source here https://v1.reactnavigation.org/docs/navigation-actions.html#navigate)
note: NavigationActions.navigate receives parameters in different way but works the same way.
so this working for me
import { NavigationActions } from 'react-navigation';
let {navigate} = NavigationActions;
renderRow(property) {
return (
<ListItem
property={property}
onPress={() => { navigate({
routeName: 'OtherRoute'
});
}}/>
);
}
<MyComponent navigation={this.props.navigation}/>
Main problem is here. You didn't define your prop navigation in component. You should add this.
Here's how you can use navigation.navigate inside a functional component:
import { Text, TouchableHighlight } from 'react-native';
const MyComponent = ({ navigation }) => (
<TouchableHighlight
onPress={() => navigation.navigate('OtherRoute')}
underlayColor="blue"/>
<Text>Click to Navigate!</Text>
</TouchableHighlight>
);
export default MyComponent;
When you render MyComponent, you will need to pass navigation as a prop. For example, assume HomeContainer is a screen component:
import React from 'react';
import MyComponent from './MyComponent';
export default HomeContainer extends React.Component {
render() {
return (
<MyComponent navigation={this.props.navigation}/>
);
}
}
Change your renderRow method to the following:
renderRow(property) {
return (
<ListItem
property={property}
onPress={() => { this.props.navigation.navigate('OtherRoute'); }}/>
);
}
where 'OtherRoute' is the name of the route you want to navigate to for that row.
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>)
}
}