how to a call static function (eg: static navigationOptions) from another function in react native - react-native

how can i call a static function (static navigationOptions) from any other function in react native?
It fails when using the this keyword, but is it possible to render static navigationOptions again by calling it?

If you want to change navigation options dynamically, try like this
static navigationOptions = ({ navigation }) => {
return {
title: navigation.getParam('otherParam', 'A Nested Details Screen'),
};
};
this.props.navigation.setParams({otherParam: 'Updated!'})
Another method
static navigationOptions = ({ navigation }) => {
const {state} = navigation;
return {
title: `${state.params.title}`,
};
};
ChangeThisTitle = (titleText) => {
const {setParams} = this.props.navigation;
setParams({ title: titleText })
}
call this.ChangeThisTitle('your title') wherever you want

They only way to achieve it is using navigation params. So set your headerleft property flag or value using setParams. That will solve the issue. Below mentioned code should be used in your class.
static navigationOptions = ({ navigation }) => {
const { params = {} } = navigation.state;
let buttonView =
<TouchableOpacity style={navItemStyle} activeOpacity={0.7} onPress={() => { params.logoutClick() }}>
<Text style={navItemTxt}> Logout</Text>
</TouchableOpacity >
return {
title: 'Home',
headerLeft: params.showHeaderLeft && buttonView
};
};
componentDidMount() {
this.props.navigation.setParams({
showHeaderLeft: this.props.headerFlag,
//headerFlag used above is your value and showHeaderLeft is the name of the param
});
}

Related

How to set navigation params from outside navigation stack?

I have a header in my app that needs to render a different button depending on whether or not the user has notifications. This is how I currently have it set up in my pages:
static navigationOptions = ({ navigation }) => {
return {
title: 'My Profile',
headerRight: () => (
<Button
type="clear"
icon={() => <Icon
type="material-community"
size={25}
name={UserProvider.bNotifications ? 'bell' : 'bell-outline'}
color={UserProvider.bNotifications ? COLORS.WARNING : COLORS.WHITE}
/>}
onPress={() => navigation.navigate('Notifications', null)}
/>
)
}
};
The problem is, if UserProvider.bNotifications changes value, the header button doesn't update unless the page is changed / rerendered.
I want to switch to use the navigation property that is passed into those navigationOptions, but I don't no how to access it from outside the navigation stack. UserProvider is a static class (NOT a component) so I can't access the navigation prop through the usual manner (or by using the useNavigation hook).
I do have a NavigationProvider class that has access to the NavigationContainer for the app. I use it to trigger navigation without components. Is there some way I can set the params on the navigation property using that same reference?
NavigationProvider:
import { NavigationActions } from 'react-navigation';
let _navigator;
function getNavigator() {
return _navigator;
}
function setTopLevelNavigator(navigatorRef) {
_navigator = navigatorRef;
}
function navigate(routeName, params) {
_navigator.dispatch(
NavigationActions.navigate({
routeName,
params,
})
);
}
function goBack() {
_navigator.dispatch(
NavigationActions.back()
);
}
export default {
navigate,
setTopLevelNavigator,
getNavigator,
goBack
};
The ref is set like this in my top level App component:
<AppContainer
ref={navigatorRef => {
console.log(navigatorRef.props.navigation);
NavigationProvider.setTopLevelNavigator(navigatorRef);
}}
/>
EDIT - UserProvider
This is just the gist of my UserProvider class, but should convey how it works.
export default class UserProvider {
private static _bNotifications: boolean;
static get bNotifications(): boolean {
if (!this.hasInitNotifications)
this.initNotficationWatch();
return this._bNotifications;
}
static set bNotifications(bNotifications: boolean) {
this._bNotifications = bNotifications;
}
static initNotficationWatch() {
//Firebase listener on notification
if(notifications){
this.bNotifications = true;
} else {
this.bNotifications = false;
}
}
}
How to set navigation params from outside navigation stack?
to do this you have to utilize the getParam method that comes from the navigation prop. the way I would di it would be to set a variable to a parameter that would equal to UserProvider.bNotifications.
static navigationOptions = ({ navigation }) => {
let notifications = navigation.getParam('notifications')
return {
title: 'My Profile',
headerRight: () => (
<Button
type="clear"
icon={() => <Icon
type="material-community"
size={25}
name={notifications ? 'bell' : 'bell-outline'}
color={notifications ? COLORS.WARNING : COLORS.WHITE}
/>}
onPress={() => navigation.navigate('Notifications', null)}
/>
)
}
};
you can set the param to an initial value by adding it as a second argument if needed navigation.getParam('paramName', 'param initial value')
To update the parameter you need to use the setParams method. For this you can use the useNavigation hook.
You can also do this inside of a functions instead of a element
// remember to const navigation = useNavigation()
<Button
title="Update param"
onPress={() => navigation.setParams({notifications: 'new value'})}
/>
you can also initiate the value this way... but I would recommend to initialize the value inside your navigationOptions
I haven't tested the code but it should work
RN DOCS: https://reactnavigation.org/docs/2.x/headers/

How can i hide and show stack navigator header in react-native?

How can I hide and then show header(stack navigator) by pressing a button ?
static navigationOptions = ({ navigation }) => {
return {
header : null
}
}
This code set header to null and hide header but i can't show it again.
You can try something like this
static navigationOptions = {
headerVisible: this.state.headerVisible,
};
And In the constructor Initialise the state by
this.state = {headerVisible: true}
And on the buttonPress You can change the state by
<Button onPress={() => this.setState({headerVisible: !this.state.headerVisible})} />
Do you could try this?
this.state={
header: null
}
static navigationOptions = {
header: this.state.header,
};
...
headerfunc(){
if(this.state.header === null){
this.setSate({
header: ""
});
}else{
this.setSate({
header: null
});
}
}
...
<Button onPress={() => this.headerfunc()} />
You can add a custom function to handle the header visibility.
Create a handler function in your screen component,
toggleHeader=()=>{
let currentVal = this.props.navigation.getParam('isHeaderVisible', true);
this.props.navigation.setParams({ isHeaderVisible: !currentVal });
}
Add this handler function to your Button
render(){
...
<Button onPress={() => this.toggleHeader()} />
...
}
Finally, add static navigationOptions in your screen,
static navigationOptions = ({navigation}) => {
let headerVisible = navigation.getParam('isHeaderVisible',true);
return {
headerVisible
}
}
Thanks for every one. headerVisible property doesn't work.
There is another property called headerMode, it just works in stack navigator's config and we can't change it in our screen :
const StackNaviagtor = createStackNavigator({
showScreen: {
screen: MyScreen
}
}, {
headerMode: 'none'
})
only header property in navigationOption work and we can change it in our screen
the solution is :
import { Header } from "react-navigation";
static navigationOptions = ({ navigation }) => {
return {
header: navigation.getParam('isFullscreen') ? null : (headerProps) => <Header {...headerProps} />
}
and then:
render() {
let isFullscreen = this.props.navigation.getParam('isFullscreen');
return (
<Button title='Full Screen' onPress={() => { this.props.navigation.setParams({ isFullscreen: !isFullscreen }) }} />
)

How to override navigation options in functional component?

To override navigation options using class components, it would be something like
export default class SomeClass extends Component {
static navigationOptions = ({ navigation }) => {
return {
title: navigation.getParam('headerTitle'),
}
}
componentDidMount() {
this.props.navigation.setParams({ headerTitle: someVariableThatComesFromExternalCall })
}
...
}
But how can I do this using functional component??
export default function SomeFunctionalCompoenent({ navigation }) {
// How and Where do I change the header title ?
useEffect(() => { navigation.setParams({ headerTitle: someVariableThatComesFromExternalCall })})
return (
...
)
}
You still need to define navigationOptions on your functional component. You do it like this:
export default function SomeFunctionalComponent({ navigation }) {
useEffect(() => {
navigation.setParams({
headerTitle: someVariableThatComesFromExternalCall
})
}, [])
}
SomeFunctionalComponent.navigationOptions = ({ navigation }) => {
return {
title: navigation.getParam('headerTitle'),
}
}
I've got a suspicion the accepted answer isn't for the currently latest version of react navigation (5), and it definitely doesn't work for this version, so here's a working example for #react-navigation/native v5.7.2 :
export default function SomeFunctionalComponent({ navigation }) {
useLayoutEffect(() => {
navigation.setOptions({
headerTitle: 'some other title',
})
}, [])
}
I've used this to access react context - to get the user's name and avatar so I can set a nice title bar for them. I've pasted in the code for this in case it helps anyone:
import React, { useContext, useLayoutEffect } from 'react';
import UserContext from '../context/UserContext';
const HomeScreen = ({ navigation }) => {
const userContext = useContext(UserContext);
useLayoutEffect(() => {
navigation.setOptions({
title : userContext.name,
headerLeft : () => (
<TouchableOpacity
onPress={() => {
navigation.openDrawer();
}}
>
<FastImage
style={styles.userPhoto}
resizeMode={FastImage.resizeMode.cover}
source={{ uri: userContext.avatar }}
/>
</TouchableOpacity>
),
});
}, [ userContext ]);
return (
// etc
);
}

How to update the header while the component is still rendered using React Navigation?

I'm writing a React Native app and I'm using React Navigation (V2) with it. I want to update the navigationOptions and add a new button, after my component has updated. Here is the code with which I tried it:
static navigationOptions = ({ navigation }) => {
const options = {
headerTitle: SCREEN_TEXT_MENU_HEADER,
headerStyle: {
borderBottomWidth: 0,
marginBottom: -5
}
};
if (navigation.getParam("drawer", true)) {
options["headerLeft"] = (
<HeaderIconButton
onClick={() => {
navigation.openDrawer();
}}
icon={require("../../assets/icons/burgerMenu.png")}
/>
);
}
if (navigation.getParam("renderBillButton", false)) {
options["headerRight"] = (
<HeaderIconButton
onClick={() => {
navigation.navigate("BillScreen");
}}
type="primary"
icon={require("../../assets/icons/euro.png")}
/>
);
}
return options;
};
componentDidUpdate = prevProps => {
const { navigation, orders } = this.props;
if (prevProps.orders.length !== orders.length) {
navigation.setParams({
renderBillButton: orders.length > 0
});
}
};
The problem with this approach is, that the navigationOptions do not get reset after componentDidUpdate(). How can I dynamically adjust the header with React Navigation?
You can use this.props.navigation.setParams() function to update the navigation state params.
Reference: https://reactnavigation.org/docs/en/headers.html#updating-navigationoptions-with-setparams
Okay here is what went wrong: I also had to call the same code within componentDidMount(), otherwise it would not affect the page upon loading. So in addition to the code of my question I added:
componentDidMount = () => {
const { navigation, order } = this.props;
navigation.setParams({
renderBillButton: orders.length > 0
});
}

React native navigation class function in header

I've got a problem with react native navigation and nested navigators.
Basically, the nested navigators (tab in a page) work pretty well. But when i add a button in the header with the _saveDetails function, it throw me an undefined function if i'm in the Players tab, and it works well when i'm on the Teams tab
Does anyone have an idea of what am i doing wrong? Thanks.
class HomeScreen extends React.Component {
static navigationOptions = ({ navigation }) => {
const { params = {} } = navigation.state;
return {
headerRight: <Button title="Save" onPress={() =>
params.handleSave()} />
};
};
_saveDetails() {
console.log('clicked save');
}
componentDidMount() {
this.props.navigation.setParams({ handleSave: this._saveDetails });
}
render() {
return (
<View />
);
}
}
const MainScreenNavigator = TabNavigator({
Players: { screen: HomeScreen},
Teams: { screen: HomeScreen},
});
const SimpleApp = StackNavigator({
Home: { screen: MainScreenNavigator },
Player: { screen: PlayerPage },
});
Please try this one and let me know if you fetch any other problem. Just convert your code according to below code.
static navigationOptions = {
header: (navigation, header) => ({
...header,
right: (
navigation.navigate('Settings')}>
Settings
)
})
}
Thanks
Just change your code become like this
class HomeScreen extends React.Component {
static navigationOptions = ({ navigation }) => {
// const { params = {} } = navigation.state; //delete this
return {
headerRight: <Button title="Save" onPress={() =>
navigation.state.params.handleSave()} /> // add navigation.state
};
};
.....