How to use createMaterialTopTabNavigator as a component - javascript

Hey I have a search screen "search for songs/artists" So after sending the request i want to appear a "Top Tabs", So I add a Top tab "createMaterialTopTabNavigator" inside separate files and then import it as a component to use it inside Search Screen like this <SearchTabs /> But i got an error
Invariant Violation: The navigation prop is missing for this
navigator. In react-navigation v3 and v4 you must set up your app
container directly. More info:
https://reactnavigation.org/docs/en/app-containers.html
lib
"react-navigation": "^4.1.0",
"react-navigation-drawer": "^2.3.3",
"react-navigation-stack": "^2.0.16",
"react-navigation-tabs": "^2.7.0",
Top Tabs Code
import {createMaterialTopTabNavigator} from 'react-navigation-tabs';
import resultArtists from './resultArtists';
import resultSongs from './resultSongs';
const SearchTabNavigator = createMaterialTopTabNavigator(
{
Songs: {
screen: resultSongs,
navigationOptions: {
tabBarLabel: 'Songs',
},
},
Artists: {
screen: resultArtists,
navigationOptions: {
tabBarLabel: 'Artists',
},
},
},
);
export default SearchTabNavigator;
then i import it in createStackNavigator 'Root.js Navigation file' like this
SearchTabs: {
screen: SearchTabNavigator,
},
here's Search Code "That contains input then i want to appear the top tabs"
class Search extends PureComponent {
render() {
return (
<Container style={styles.container}>
<View style={styles.searchHeader}>
<Input
onChangeText={text => this.search(text)}
value={this.state.searchText}
onSubmitEditing={this.onSearch}
returnKeyType="search"
placeholderTextColor="white"
style={styles.searchInput}
/>
</View>
<SearchTabNavigator />
</Container>
)
}
}
export default Search;
The final result should be something like this
What I tried
I add new createAppContainer to wrap the Top tabs like this in 'Top Tabs file'
export const Tabs = createAppContainer(SearchTabNavigator);
And it's working fine.
but i think it's the wrong way, to add two AppContainer in the same app :\
And when i want to navigate from any item "songs" to Player screen 'it's in Different AppContainer' it's not working!.

Related

How to disable header in createDrawerNavigation from Reac Navigation in React Native

Background
While building a React Native application and using a DrawerNavigator from React Navigation I ended up needing to customize the header that comes with a createDrawerNavigator. I found that I can customize a createStackNavigator though.
createStackNavigator
Can hide the header
Can customize the header.
createDrawerNavigator
Can NOT hide the header
Can NOT customize the header.
Question
How do I hide or customize the header that automatically is added to my app when using the createDrawerNavigator from React Navigation?
Example
createStackNavigator
I can hide the header that appears when using createStackNavigator like this,
const Secure = createStackNavigator(
{
Drawer: {
screen: drawer,
},
},
{
initialRouteName: 'Drawer',
headerMode: 'none',
},
);
createDrawerNavigator
When using createDrawerNavigator nothing I try works to hide or customize the header. I have also searched the documentation and can not find anything referencing how to deal with the header in React Native navigation Version 3 for createDrawerNavigator.
This code will be help the header none for custom drawer component.
const customDrawerContentComponent = (props) => {
Contact: {
screen: ContactScreen ,
navigationOptions: () => ({
header: null
})
}
}
const AppDrawerNavigator = createDrawerNavigator({
Home: {
screen: HomeScreen,
navigationOptions: () => ({
header: null
})
}
}, {
contentComponent: customDrawerContentComponent,
})
Like the answer from Kazi said, you can pass headerMode: null to hide the header from the drawerNavigators and the stacknavigator. The problem with this is that you end up with no headers at all.
So if you want headers for specific screens, there's a header component on react-native-elements that you can add to each screen you want a header on.
Here's an example:
<React.Fragment>
<Header
statusBarProps={{ barStyle: 'light-content' }}
barStyle="light-content"
leftComponent={
<SimpleIcon
name="menu"
color="#34495e"
size={20}
/>
}
centerComponent={{ text: 'HOME', style: { color: '#34495e' } }}
containerStyle={{
backgroundColor: 'white',
justifyContent: 'space-around',
}}
/>
</React.Fragment>
In this example, I had to wrap it on React.Fragment tags because I put this part of the code in the beginning of the render method. I also added a title to the screen and the hamburguer button to open the drawer.
So, basically what I did is, hide the header on both stackNavigators and drawerNavigators then add the component to each of your screens that you do want a header on.

How not to unmount previously opened screen of Drawer Navigator

I am using react-native-navigation and trying to create a DrawerNavigator which does not unmount the previously opened screens just like how TabNavigator works. Because one of my screens contains a webview and I do not want it to reload everytime I change screens.
Here is some sample code in App.js..
const Drawer = DrawerNavigator(
{
Home: { screen: Home },
PageWithWebview: { screen: PageWithWebview},
Settings: { screen: Settings },
},
{
initialRouteName: "Home",
contentComponent: props => <SideBar user={global.user} />
}
);
const AppNavigator = StackNavigator(
{
Drawer: { screen: Drawer },
},
{
initialRouteName: "Drawer",
headerMode: "none"
}
);
export default () =>
<Root>
<AppNavigator/>
</Root>;
And in my Sidebar component I have buttons to navigate to a different route depending on what is selected .
onPress={() => this.props.navigation.navigate(selected, { userDetails: global.user })}
In the later versions of react native navigation they added the unmountInactiveScreens property for the DrawerNavigator
unmountInactiveScreens
Whether a screen should be unmounted when navigating away from it. Unmounting a screen resets any local state in the screen as well as state of nested navigators in the screen. Defaults to false.

How do I access react-navigation from inside a component that isn't the HomeScreen?

I'm building a React Native app. I have imported createStackNavigator from react-navigation. I'm able to get it working on my Home screen - I click a button, it brings me to a new component. This is the code that I'm using to bring it into my Home.js
// src/components/Home/Home
export class Home extends Component {
render() {
return (
<React.Fragment>
<Button
title="Test button"
onPress={() => this.props.navigation.navigate('Roads')}
/>
<StatusBar />
<Header />
<Menu />
</React.Fragment>
);
}
}
const RootStack = createStackNavigator(
{
Home: Home,
Roads: Roads,
},
{
initialRouteName: 'Home',
}
);
export default class App extends React.Component {
render() {
return <RootStack />;
}
}
My Home page takes in a Menu which has a list of MenuItems. I am trying to get the MenuItems to jump to the appropriate pages. When I try to bring in the navigation inside MenuItem.js's render method, like so:
// src/components/Roads/Roads
render() {
const { navigate } = this.props.navigation;
console.log(this.props, "props is here");
I get the following error message:
TypeError: undefined is not an object (evaluating 'this.props.navigation.navigate').
Do I need to pass the navigator down in props to Menu.js and then to MenuItem.js? The docs give examples but it seems to be examples that assume you jam all your code into one file rather than across several components.
Have I set this up correctly?
When using a Navigator from react-navigation only the components you declare as Screens inherit the navigation prop (in your case Home and Roads)
This means that you will need to pass it as a prop to its children as you said:
<Menu navigation={this.props.navigation} />
<MenuItem navigation={this.props.navigation} />
In case anyone is wondering how to navigate from a component that isn't inside a Navigator then I suggest reading this part of the react-navigation documentation
https://reactnavigation.org/docs/en/navigating-without-navigation-prop.html

Linking to specific mui-tab using react-router-dom

I have a set of tabs using material ui as the base. I want to be able to link to one of the tabs so that that tab is open when landing on the page. All very simple for me outside of the react application(add anchor).
I've searched for solutions but no good, I suspect I need to do something with the main router and path and pass a property that tells the tab which one to be open. Then simply add that property on the link to pass to the page?
I will link to the tab(from a different page) using <Link>
<Link to="/page/tabpage" title="Link to tab 2">Link to tab 2</Link>
I imagine I will need to pass a value from this link to the URL which then opens up that specific tab, something like:
<Link to="/page/tabpage#tab2" title="Link to tab 2">Link to tab 2</Link>
My app route path for this page looks like this:
import { Route } from 'react-router-dom';
<Route path={`${match.url}/page/tabpage`}
component={asyncComponent(() => import('./routes/tabpage'))} />
The tabpage looks like something like the following:(for the general idea)
import React from "react";
import { connect } from "react-redux";
import PropTypes from "prop-types";
import { Link } from "react-router-dom";
import Tabs, { Tab } from "material-ui/Tabs";
import { whenGapiReady } from "../../../util/gapiHelper";
function TabContainer({ children, dir, className }) {
return (
<div dir={dir} className={className} style={{ padding: 8 * 3 }}>
{children}
</div>
);
}
TabContainer.propTypes = {
children: PropTypes.node.isRequired,
dir: PropTypes.string.isRequired
};
class tabpage extends Component {
constructor(props) {
super(props);
this.state = {
value: 0
};
}
componentWillMount() {
whenGapiReady(() => {});
}
handleChange = (event, value) => {
this.setState({ value });
};
render() {
return (
<div>
<Tabs
initialSelectedIndex={this.state.value}
value={this.state.value}
onChange={this.handleChange}
indicatorColor="primary"
textColor="primary"
fullWidth
scrollable
scrollButtons="on"
classes={{ root: styles.root }}
>
<Tab className="tab" label="Tab 1" />
<Tab className="tab" label="Tab 2" />
</Tabs>
<TabContainer dir={theme.direction}>TAB 1 CONTENT ECT..</TabContainer>
<TabContainer dir={theme.direction}>TAB 2 CONTENT ECT..</TabContainer>
</div>
);
}
}
const mapStateToProps = ({}) => {};
export default tabpage;
Use with redux or local storage to manage active tabs and their content.
Map your tabs and render links.
Then render different components in different routes with links matched paths.
You may find some of my code usefull: https://github.com/SimonMulquin/EventsPlanning/tree/master/client/src/ui

Route should declare a screen. [ React Native Navigation Error]

Hi I am new to react native and I am facing strange issue with routing. I am doing something wrong but need someone to guide me.
index.android.js
import { LandingScreen } from './src/components/landing_screen.js'
import HomeScreen from './src/app_component.js'
import { StackNavigator } from 'react-navigation';
const SimpleApp = StackNavigator({
Home: { screen: HomeScreen },
Landing: { screen: LandingScreen},
});
AppRegistry.registerComponent('HomeScreen', () => SimpleApp);
app_component.js
// Other imports ...
export default class HomeScreen extends Component {
static navigationOptions = {
title: 'Home Screen',
};
render() {
const { navigate } = this.props.navigation;
return (
<View style={styles.container}>
<Text style={styles.welcome}>
Welcome to React Native!
</Text>
<Text style={styles.instructions}> Hello CHannoo!!!</Text>
<Text style={styles.instructions}>
To get started, edit index.android.js
</Text>
<Text style={styles.instructions}>
Double tap R on your keyboard to reload,{'\n'}
Shake or press menu button for dev menu
</Text>
<Button
title="Go to 2nd Page"
onPress={() =>
// alert('hello');
navigate('LandingScreen')
// navigate('Home', { name: 'Jane' })
}
/>
</View>
);
}
componentDidMount () {
SplashScreen.close({
animationType: SplashScreen.animationType.scale,
duration: 850,
delay: 500,
})
}
}
landing_screen.js
export default class LandingScreen extends Component {
static navigationOptions = {
title: 'Landing Screen Title',
};
render() {
return (........)
}
It works fine if we remove route Landing. But when we add this route we get error.
Route 'Landing' should declare a screen. For example ......
Your LandingScreen has been exported as default but you imported it by name.
your import statement is like this:
import { LandingScreen } from './src/components/landing_screen.js'
replace it with line below (without curly brackets):
import LandingScreen from './src/components/landing_screen.js'
it should solve the problem.
BUT you will probably get a new error as #Medet pointed out because you have to change this line:
navigate('LandingScreen')
to:
navigate('Landing')
since your screen name is Landing.
You calling navigate('LandingScreen')
But screen name is Landing
+ #Dusk's answer should solve

Categories

Resources