How do you handle cases when you have, say, a form component, and you need to submit a part of the component's state using button in navigation bar?
const navBtn = (iconName, onPress) => (
<TouchableOpacity
onPress={onPress}
style={styles.iconWrapper}
>
<Icon name={iconName} size={cs.iconSize} style={styles.icon} />
</TouchableOpacity>
)
class ComponentName extends Component {
static navigationOptions = {
header: (props) => ({
tintColor: 'white',
style: {
backgroundColor: cs.primaryColor
},
left: navBtn('clear', () => props.goBack()),
right: navBtn('done', () => this.submitForm()), // error: this.submitForm is not a function
}),
title: 'Form',
}
constructor(props) {
super(props);
this.state = {
formText: ''
};
}
submitForm() {
this.props.submitFormAction(this.state.formText)
}
render() {
return (
<View>
...form goes here
</View>
);
}
}
Simple Design Pattern
Just as a follow-up to @val's excellent answer, here's how I structured my Component so that all the params are set in the componentWillMount
. I find this keeps it simpler and is an easy pattern to follow for all other screens.
static navigationOptions = ({navigation, screenProps}) => {
const params = navigation.state.params || {};
return {
title: params.title,
headerLeft: params.headerLeft,
headerRight: params.headerRight,
}
}
_setNavigationParams() {
let title = 'Form';
let headerLeft = <Button onPress={this._clearForm.bind(this)} />;
let headerRight = <Button onPress={this._submitForm.bind(this)} />;
this.props.navigation.setParams({
title,
headerLeft,
headerRight,
});
}
componentWillMount() {
this._setNavigationParams();
}
_clearForm() {
// Clear form code...
}
_submitForm() {
// Submit form code...
}
Send a binded function with setParams
, then you will have access to component's state
within that function.
Example:
constructor(props) {
super(props);
this._handleButtonNext = this._handleButtonNext.bind(this);
this.state = { selectedIndex: 0 }
}
componentDidMount() {
this.props.navigation.setParams({
handleButtonNext: this._handleButtonNext,
});
}
_handleButtonNext() {
let action = NavigationActions.setParams({
params: { selectedImage: images[this.state.selectedIndex] }
});
this.props.navigation.dispatch(action);
}
Now you can have a button handler related to component's state
.
static navigationOptions = ({ navigation }) => {
const { state, setParams, navigate } = navigation;
const params = state.params || {};
return {
headerTitleStyle: { alignSelf: 'center' },
title: 'Select An Icon',
headerRight: <Button title='Next' onPress={params.handleButtonNext} />
}
}
On your componentDidMount, you can use
this.navigation.setParams({
myTitle: this.props.myTitle
})
Then, pass a function to your header on static props. This function has access to the params you set before
Thanks to rafaelcorreiapoli
You are getting this error because you are using props and state before declaring constructor()
. As in constructor we first call super(props) so that we can use props in our component. Please do the following to get desired result.
constructor(props) {
super(props);
this.state = {
formText: ''
};
static navigationOptions = {
header: (props) => ({
tintColor: 'white',
style: {
backgroundColor: cs.primaryColor
},
left: navBtn('clear', () => props.goBack()),
right: navBtn('done', () => this.submitForm()), // error: this.submitForm is not a function
}),
title: 'Form',
}
}
Cheers:)