How can I completely replace the react-navigation header? - react-native

I'm not simply trying to replace the left middle or right components, I want to replace the whole header so that I can use the Toolbar from react-native-material-ui.

You can override a header property in your navigationOptions:
import { HeaderBackButton } from 'react-navigation'
class Foo extends React.Component {
static navigationOptions = (navigationProps) => {
return {
header: (props) => (
<MyCustomHeaderContainer>
<HeaderBackButton
onPress={() => props.navigation.goBack(null)}
tintColor="#fff"
/>
<ContentComponent />
</MyCustomHeaderContainer>
),
};
}
}
This assumes that Foo component is routable, e.g.
StackNavigator({
Foo: {
screen: Foo,
},
});
UPD: You can also specify navigationOptions at the moment you create a navigator. This may be handy in some cases, e.g. nested navigation:
const MainNavigator = TabNavigator({...});
export default StackNavigator({
MainNavigator: {
screen: MainNavigator,
navigationOptions: {
header: navigationProps => <YourHeaderComponent {...navigationProps} />
},
}
}

Related

How to pass a string to screens into a BottomTabNavigator

I have a BottomTabNavigator with 4 sreens inside of it, I would like to pass a string into some of them.
How can I do that ? Thank you.
class Main extends Component {
static navigationOptions = {
title: 'Developpe Inclinné',
headerTintColor: '#fff',
headerStyle: {
backgroundColor: '#e8142d',
},
};
render() {
const myPath='aRouteForFirebase'
return (
<AppContainer myPath={myPath} />
);
}
}
const TabNavigator = createBottomTabNavigator({
DeveloppeInclinne,
Chrono,
Session, // needs the props
Resultats // // needs the props
})
const AppContainer = createAppContainer(TabNavigator);
Here is a better implementation:
class Main extends Component {
constructor(props) {
super(props)
this.state = {
myPath: 'aRouteForFirebase',
}
this.AppContainer = createAppContainer(this.TabNavigator)
}
TabNavigator = createBottomTabNavigator({
DeveloppeInclinne,
Chrono,
Session: { screen: () => <Session myPath={this.state.myPath} />},
Resultats { screen: () => < Resultats myPath={this.state.myPath} />}
})
render() {
const { AppContainer } = this
return (
<AppContainer />
)
}
}
Just for clarification:
class Main extends Component {
static navigationOptions = {
title: 'Developpe Inclinné',
headerTintColor: '#fff',
headerStyle: {
backgroundColor: '#e8142d',
},
};
render() {
const myPath='aRouteForFirebase'
const TabNavigator = createBottomTabNavigator({
DeveloppeInclinne,
Chrono,
Session: { screen: () => <Session myPath={myPath} />},
Resultats { screen: () => < Resultats myPath={myPath} />}
}
const AppContainer = createAppContainer(TabNavigator);
return (
<AppContainer />
);
}
}
However I don't think this is good looking code, maybe you should think about integrating Redux
I can't find anything in react-navigation documentation which supports this. But I may be wrong. I can suggest one other way of doing it. Create a HOC and wrap your components with it. They all will have access to the common string.
const SomethingCommonHOC = (Component, extraProps ) => {
return class SomeComponent extends React.Component {
render() {
return <Component {...this.props} {...extraProps}/>;
}
};
};
// Use it something like this.
SomethingCommonHOC(Session);
Thanks
Edit: I understand it is difficult to explain actually. That's the reason i am not big fan of HOCs. :). I will give more try to explain you the edit required.
Create a new file:
Put this component definition in it:
const CommonHOC = (Component, extraProps) => {
return class SomeComponent extends React.Component {
render() {
return <Component {...this.props} {...extraProps} />;
}
};
};
export default CommonHOC
Then import it in your component files , in your case DeveloppeInclinne, Chrono, Session, Resultats.
In component where your need to pass common string: Let's say you are editing in session component file
import CommonHOC from the "path to CommonHOC"
export default CommonHOC(Session, {
myString: "myString"
})
Note: you can string like constant dynamic by converting 2nd param a the object and spreading inside the common component
You can do this:
const TabNavigator = createBottomTabNavigator({
DeveloppeInclinne,
Chrono,
Session: { screen: props => <Session {...props} />},
Resultats { screen: props => < Resultats {...props} />}
}
// in class Session ...
console.log(this.props.myPath)
=> aRouteForFirebase

Remove navigation header on screen for react native app

I want to remove header from my screen where I use bottom tab navigator.
Here is code example:
export class Home extends Component {
render() {
return <ProductList />;
}
}
export class Settings extends Component {
render() {
return <Chat />;
}
}
const Main = createBottomTabNavigator({
Home: {
screen: Home,
navigationOptions: {
header: null,
},
},
Settings: {
screen: Settings,
},
});
navigationOptions for header seams to be ignored
navigationOptions: {
header: null,
},
But when I use navigation option on single page without createBottomTabNavigator it works.
Any ideas?
You can use this instead of above
export class Home extends Component {
static navigationOptions = {
header: {
visible: false,
}
}
render() {
return <ProductList />;
}
}
export class Settings extends Component {
render() {
return <Chat />;
}
}
const Main = createBottomTabNavigator({
Home: {
screen: Home
},
Settings: {
screen: Settings,
},
},
{
headerMode: 'screen'
});
Hope this will help you

pass props in nested stackNavigator

I'm a beinner in React-Native and i'm using stackNavigator from react-navigation package to create a Wizard. But i can't pass parameters between different screens of stacks:
class TaskWizard extends React.Component {
constructor(props) {
super(props)
let {service} = this.getNavigationParams()
this.state = {
model : {service.fields}
}
}
getNavigationParams() {
return this.props.navigation.state.params || {}
}
}
const TaskWizardStack = createStackNavigator({
Wizard : {
screen : TaskWizard,
},
})
const PostTaskStack = createStackNavigator({
// some screens here then Task wizard
Deep : {
screen : Deep
}
TaskWizard : {
screen : TaskWizardStack
}
})
export default PostTaskStack
I know i can pass parameters to a screen like this from Deep component :
<View>
<TouchableOpacity
onPress={() => this.props.navigation.navigate('TaskWizard', {
service: {id : 1, fields : [{}]} },
})
/>
</View>
This will pass service parameter from inside of Deep component to TaskWizard Stack. I need to pass it from TaskWizard to every child screens like Wizard. Is it possible?
Try using screenprops to pass the data to other components
https://reactnavigation.org/docs/en/stack-navigator.html#navigator-props
Code below works for me
export const AdminBottomNavigator = createBottomTabNavigator(
{Home: {screen: SchoolDashboard},
Students: {screen: StudentList},
Message: {screen: Dashboard},
Settings: {screen: StudentList},},
defaultNavigationOptions: ({ navigation }) =>
({tabBarIcon: ({ focused, horizontal, tintColor }) =>
{let screenProps=navigation.getScreenProps();}})})

How to handle click event on tab item of TabNavigator in React Native App using react-navigation?

I am programming React Native App. I am using react-navigation for navigating screens.
I have 2 Stack Navigators, they are stayed in a Tab Navigator. I want handle click event when I press tab item on TabBar to refresh its view.
export const HomeStack = StackNavigator({
Home: {screen: ScreenHome},
Detail: {screen: ScreenDetail}
})
export const UserStack = StackNavigator({
User: {screen: ScreenUser}
})
export const Tabbar = TabNavigator({
HomeTab: {
screen: HomeStack,
},
UserTab: {
screen: UserStack,
}
}, {
tabBarComponent: ({ jumpToIndex, ...props}) => (
<TabBarBottom
{...props}
jumpToIndex={(index) => {
if(props.navigation.state.index === index) {
props.navigation.clickButton(); //----> pass props params (code processes)
}
else {
jumpToIndex(index);
}
}
}
/>
),
tabBarPosition: 'bottom'
});
class TabClass extends Component{
constructor(props){
super(props)
this.clickButton = this.clickButton.bind(this)
}
clickButton(){
console.log('click button')
}
render (){
return (
<Tabbar clickButton={()=> this.clickButton()}/>
)
}
}
I want to pass clickButton() function from TabClass Component to the code which processes event click tab bar. When if(props.navigation.state.index === index), I want it will call clickButton(). I try it but it doesn't work.
Is there any way to solve my matter?
I tried onNavigationStateChange(prevState, currentState).
class TabClass extends Component{
constructor(props){
super(props)
this.clickButton = this.clickButton.bind(this)
}
clickButton(){
console.log('click button')
}
_handleNavagationStateChange(prevState, currentState){
console.log('handle navigation state change')
}
render (){
return (
<Tabbar onNavigationStateChange={(prevState, currentState) => {
this._handleNavagationStateChange(prevState, currentState)
}}
clickButton={()=> this.clickButton()}
/>
)
}
}
However, _handleNavagationStateChange(prevState, currentState) only run when navigation state changes (for examples, if I stay at HomeTab, I click User Tab Item, this function will run; if I stay at HomeTab, I click Home Tab Item, this function will not run).
Is there any way to handle click event on tab item.
according to the newest documentation here, you can use navigationOptions: {navigationOptions: () => doWhatever()} to handle tab bar taps.
From the react-navigation 4.x docs, you can override tabBarOnPress within navigationOptions:
tabBarOnPress: ({ navigation, defaultHandler }) => {
defaultHandler(); // Call the default handler to actually switch tabs
// do extra stuff here
},
Please try the code following when customize the event touch of TabBar:
import { TabBarBottom, TabNavigator, StackNavigator } from 'react-navigation';
export const MainScreenNavigator = TabNavigator({
Home: { screen: HomeViewContainer },
Search: { screen: SearchViewContainer },
}, {
tabBarComponent: ({ jumpToIndex, ...props, navigation }) => (
<TabBarBottom
{...props}
jumpToIndex = { tabIndex => {
const currentIndex = navigation.state.index;
if (tabIndex == 1) {
// do some thing. Call Native Live Stream Record
} else {
jumpToIndex(tabIndex);
}
console.log('Select tab: ', tabIndex);
}}
/>),
tabBarPosition: 'bottom',
});

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
};
};
.....