How to create a Drawer Component and adding it to multiple screens - react-native

Hi i want to create a component by using a createDrawerNavigator, and want to add it all screens could you help me.

In the below example don't copy all the syntax understand the concept from my explanation I have configured redux and many other imports you may not need so configure and include content in below files as you need.
File name - BurgerMenu.js
import React, { Component } from "react";
import SideBar from "./SideBar.js";
import News from "../../Containers/News"; // import your screens instead
import Copyright from '../../Containers/Gallery' // import your screens instead
import { DrawerNavigator } from "react-navigation";
const BurgerMenu = DrawerNavigator(
{
News: { screen: News },
RulesOfUse: { screen: RulesOfUse },
Copyright: { screen: Copyright }
},
{
contentComponent: props => <SideBar {...props} />
}
);
export default BurgerMenu;
File name - SideBar.js
In this file specify the layout, any actions like navigation, api call etc of drawer as you want which is imported to above BurgerMenu.js file
/*
SideBar.js
Component used to render contents of SideBar
*/
import React from 'react';
import { View, Modal, Text, Linking } from 'react-native';
const {
modalBackground,
topContentStyle,
bottomContentStyle
} = styles;
class SideBar extends React.Component {
constructor(props) {
super(props);
this.state = {
};
}
componentDidMount() {
}
render() {
return (
<View
elevation={5}
style={modalBackground}
>
</View>
);
}
}
export default SideBar;
And in the App.js import Burgermenu.js to StackNavigator
import React, { Component } from 'react'
import { Provider } from 'react-redux';
import { StackNavigator } from 'react-navigation';
import Splash from './src/App/Containers/Splash';
import Login from './src/App/Containers/Login';
import InformationPage from './src/App/Containers/Gallery'
import BurgerMenu from './src/App/Components/BurgerMenu/index'
import configureStore from './src/RNRedux/ConfigureStore';
// Manifest of possible screens
const PrimaryNav = StackNavigator({
Splash: { screen: Splash },
Login: { screen: Login },
Home: { screen: BurgerMenu },
InformationPage: { screen: InformationPage }
}, {
// Default config for all screens
headerMode: 'none',
initialRouteName: 'Splash',
});
export default class App extends Component {
constructor(props) {
super(props);
this.state = {
channelId: ""
};
this.store = configureStore();
}
componentDidMount() {
}
componentWillMount() {
}
render() {
return (
<Provider store={this.store}>
<PrimaryNav />
</Provider>
);
}
}
Just open the burger menu from any the screens imported to BurgerMenu.js
In my example you can open it from news.js and gallery.js which are imported to BurgerMenu.js.
Just use below functions for open and close
openBurgerMenu() {
this.props.navigation.openDrawer();
}
closeBurgerMenu() {
this.props.navigation.closeDrawer();
}

Related

Cannot access redux props inside react-navigation v3 tab navigator (getting error this.props.<function_name> is not a function)

I am having trouble connecting the tab navigator (from React-Navigation v3) to the redux provider.
So this is how my react-navigation and redux is configured:
app/
/react-redux provider
/app-container (this is the AppContainer of the main SwitchNavigator)
/welcome-screen
/login-screen
/register-screen
/home-navigator (this is the TabNavigator that is inside the SwitchNavigator)
Home navigator holds the screens to which user is directed to when he logs-in. In the first 3 screends (welcome, login and register) I can access the functions that are "connected" from redux to the screen through standard mapDispatchToProps.
This is the app component:
/**
* Entry point for the app
*/
import React, { Component } from "react";
// redux
import { Provider } from "react-redux";
import { createStore, applyMiddleware } from "redux";
import reduxThunk from "redux-thunk";
import { composeWithDevTools } from "redux-devtools-extension";
import main_app_reducer from "./modules/core/reducers/main_app_reducer";
// create redux store
const create_store = composeWithDevTools(applyMiddleware(reduxThunk))(createStore);
export const store = create_store(main_app_reducer);
// navigation
import AppContainer from "./modules/core/components/AppNavigator";
import { configure_axios } from "./helpers/axios_config";
configure_axios();
class App extends Component {
render() {
return (
<Provider store={store}>
<AppContainer />
</Provider>
);
}
}
export default App;
And then, from there we go to AppContainer:
/**
* this components ensures app navigation so that user can jump from one screen to another
*/
// navigation
import { createSwitchNavigator, createAppContainer } from "react-navigation";
// screens
import WelcomeScreen from "../screens/WelcomeScreen";
import LoginScreen from "../../auth/screens/LoginScreen";
import RegisterScreen from "../../auth/screens/RegisterScreen";
import HomeNavigator from "./HomeNavigator";
const AppSwitchNavigator = createSwitchNavigator({
// for users that are not logged in yet
Welcome: { screen: WelcomeScreen },
Login: { screen: LoginScreen },
Register: { screen: RegisterScreen },
// for logged in users
HomeNavigator: { screen: HomeNavigator },
});
const AppContainer = createAppContainer(AppSwitchNavigator);
export default AppContainer;
All of the code above works perfectly with no errors, the problem occurs inside the HomeNavigator component that you see below.
This is the HomeNavigator component:
import { createBottomTabNavigator } from "react-navigation";
import { HomeScreen } from "../screens/HomeScreen";
import { DashboardScreen } from "../screens/DashboardScreen";
const HomeNavigator = createBottomTabNavigator(
{
Home: { screen: HomeScreen },
Dashboard: { screen: DashboardScreen },
},
{
navigationOptions: ({ navigation }) => {
const { routeName } = navigation.state.routes[navigation.state.index];
return {
headerTitle: routeName,
};
},
},
);
export default HomeNavigator;
NONE of the screens inside the HomeNavigator are connected to Redux altough they are defined THE SAME WAY as the screens inside AppContainer file. For comparison let's see Login screen from AppContainer and Home screen from HomeNavigator:
LoginScreen:
import React, { Component } from "react";
import { View, Text } from "react-native";
import { connect } from "react-redux";
import { get_user_servers } from "../actions/core_actions";
export class LoginScreen extends Component {
componentDidMount() {
this.props.get_user_servers(); // this function works absolutely fine
}
render() {
return (
<View>
<Text> LoginScreen </Text>
</View>
);
}
}
const mapStateToProps = (state) => ({});
const mapDispatchToProps = { get_user_servers };
export default connect(
mapStateToProps,
mapDispatchToProps,
)(LoginScreen);
HomeScreen:
import React, { Component } from "react";
import { View, Text } from "react-native";
import { connect } from "react-redux";
import { get_user_servers } from "../actions/core_actions";
export class HomeScreen extends Component {
componentDidMount() {
this.props.get_user_servers();
// the same function as in LoginScreen but here the function does not work
// I'm getting an error = TypeError: this.props.get_user_servers is not a function (see picture below)
}
render() {
return (
<View>
<Text> HomeScreen </Text>
</View>
);
}
}
const mapStateToProps = (state) => ({});
const mapDispatchToProps = { get_user_servers };
export default connect(
mapStateToProps,
mapDispatchToProps,
)(HomeScreen);
That function (get_user_servers) is defined properly and it works fine in LoginScreen.
thanks everyone who took their time to help me, in the end it was my mistake that I overlooked. If you check out the third code-block from this question you can see that I import my components like this:
import { HomeScreen } from "../screens/HomeScreen";
import { DashboardScreen } from "../screens/DashboardScreen";
Which is wrong, I changed that to:
import HomeScreen from "../screens/HomeScreen";
import DashboardScreen from "../screens/DashboardScreen";
And now everything works fine, thanks again :)
Assuming it's the same function you're importing, please could you try to check your import of get_user_servers function from both screen : LoginScreen and HomeScreen. According to your code it look like LoginScreen ("../../auth/screens/LoginScreen") and HomeScreen ("../screens/HomeScreen") are not in the same path.
As asked above, could check the path of the files, or post it so we can help. Also could you open the remote debugger, and inside the componentWillMount you can put:
console.log(this.props)
to check if the HomeScreen is geting the function inside props.

Undefined Unstated Container in a React Native Component using React Navigation

My problem is That I want to access a Container in a component but it seems to be undefined.
undefined alert image
I am using Unstated and as you can see this is my code in the container file (login-container.js):
import { Container } from 'unstated'
class LoginContainer extends Container {
constructor(props){
super(props)
this.state = {
stepNumber: 0,
}
}
}
export default new LoginContainer()
And this is app.js:
import React, { Component } from 'react'
import { createStackNavigator, createSwitchNavigator } from 'react-navigation'
import { Provider } from 'unstated'
import LoginContainer from './containers/login-container'
import Home from './screens/home'
import Splash from './screens/splash'
import Login from './screens/login'
import Intro from './screens/intro'
export default class App extends Component {
render() {
return (
<Provider inject={[LoginContainer]}>
<AuthStack/>
</Provider>
)
}
}
const SplashStack = createStackNavigator(...)
const AppStack = createStackNavigator(...)
const AuthStack = createStackNavigator(
{
Intro: { screen: Intro},
Login: { screen: Login}
},
{
headerMode: "none",
initialRouteName: "Intro"
}
)
const SwitchNavigator = createSwitchNavigator(...)
And this would be login.js:
import React, { Component } from 'react'
import { Text, View } from 'react-native'
export default class Login extends Component {
constructor(props){
super(props)
}
render() {
// const { state: {stepNumber} } = this.props.loginContainer
alert(this.props.LoginContainer)
return (
<View>
<Text> someText </Text>
</View>
)
}
}
I previously tried to use Subscribe component to inject the container to my app but I got the same thing I am getting here.
Using
- react-native 0.58.6
- react-navigation 2.13.0 (due to some bugs in v3)
- unstated 2.1.1
What's really great about Unstated is how simple it is to implement.
Just wrap your render component in Unstated's <Subscribe to></Subscribe> tags and you're good to go. Whenever you setState() in the Container, all Components that Subscribe to it get re-rendered with the Container's updated state property values available to them.
import React, { Component } from 'react';
import { Text, View } from 'react-native';
import { Subscribe } from 'unstated';
import LoginContainer from './containers/login-container';
export default class Login extends Component {
constructor(props){
super(props)
}
render() {
return (
<Subscribe to={[LoginContainer, AnotherContainer]}>
{(container, another) => (
<View>
<Text>{container.state.stepNumber}</Text>
</View>
})
</Subscribe>
);
}
}
UPDATE: Or do it in this HOC way. After creating this:
WithUnstated.js
import React, { PureComponent } from "react";
import { Subscribe } from "unstated";
import DefaultStore from "../store/DefaultStore";
const withUnstated = (
WrappedComponent,
Stores = [DefaultStore],
navigationOptions
) =>
class extends PureComponent {
static navigationOptions = navigationOptions;
render() {
return (
<Subscribe to={Stores}>
{(...stores) => {
const allStores = stores.reduce(
(acc, v) => ({ ...acc, [v.displayName]: { ...v } }),
{}
);
return <WrappedComponent {...allStores} {...this.props} />;
}}
</Subscribe>
);
}
};
export default withUnstated;
Then wrap your component like so:
import React, { Component } from 'react';
import { Text, View } from 'react-native';
import { Subscribe } from 'unstated';
import LoginContainer from './containers/login-container';
import AnotherContainer from './containers/another-container';
class Login extends Component {
constructor(props){
super(props)
}
render() {
const {LoginContainer: container} = this.props;
return (
<View>
<Text>{container.state.stepNumber}</Text>
</View>
);
}
}
export default withUnstated(Login, [LoginContainer, AnotherContainer])

React-native with react-navigation: header not showing in screen

I do have a simple React-native app, using react-navigation for navigation. My issue is that for one of the screens the header and title is not showing, even though it is set in navigationOptions:
main.js:
import React from "react";
import { View, Text } from "react-native";
import {
createDrawerNavigator,
createAppContainer,
createStackNavigator
} from "react-navigation";
import ArticleList from "./screens/ArticleList";
import ArticleList2 from "./screens/ArticeList2";
import ArticleWebView from "./screens/ArticleWebView";
// create the Navigator to be used
const Stack = createStackNavigator({
ArticleList: { screen: ArticleList },
ArticleWebView: { screen: ArticleWebView }
});
const Drawer = createDrawerNavigator(
{
Stack: { screen: Stack },
ArticleList2: { screen: ArticleList2 }
},
{
initialRouteName: "Stack"
}
);
// The container for the navigator
const AppContainer = createAppContainer(Drawer);
class App extends React.Component {
render() {
return <AppContainer />;
}
}
export default App;
The ArticleList2 is a very simple component:
import React from "react";
import { View, Text } from "react-native";
import ArticleListComponent from "../components/ArticleListComponent";
class ArticleList2 extends React.Component {
static navigationOptions = {
title: 'Link2'
};
render() {
return (
<View>
<Text>LIst2</Text>
</View>
);
}
}
export default ArticleList2;
However, the title and header are not rendered in the app. Could anybody help please?
DrawerNavigator does not include a header. In order to create a header inside of ArticleList2 you will have to create a new StackNavigator for the component.
You have to think about and plan out the navigation flow of your app.
The Drawer section of the React Navigation documentation is a little lacking, but you can use the same principle as described in the Tab section
A stack navigator for each tab
const ArticleList2Stack = createStackNavigator({
ArticleList2: { screen: ArticleList2 }
});
const Drawer = createDrawerNavigator(
{
Stack: { screen: Stack },
ArticleList2: { screen: ArticleList2Stack }
},
{
initialRouteName: "Stack"
}
);

React Native: Invariant Violation: The navigation prop is missing for this navigator

My code is as follows:
import React, {Component} from 'react';
import {Platform, StyleSheet, Text, View} from 'react-native';
import {LoginNavigator} from './src/components/login/LoginNavigator'
import {MainNavigator} from './src/components/main/MainNavigator'
import FBSDK from 'react-native-fbsdk'
import {createSwitchNavigator} from 'react-navigation'
const { AccessToken } = FBSDK
export default class App extends Component {
constructor(props) {
super(props)
this.state = {
accessToken: null
}
}
componentDidMount() {
AccessToken.getCurrentAccessToken()
.then((data) => {
this.setState({
accessToken: data.accessToken
})
})
.catch(error => {
console.log(error)
})
}
render() {
const Navigator = makeRootNavigator(this.state.accessToken)
return <Navigator />
}
}
const makeRootNavigator = (isLoggedIn) => {
return createSwitchNavigator(
{
LoginNavigator: {
screen: LoginNavigator
},
MainNavigator: {
screen: MainNavigator
}
},
{
initialRouteName: isLoggedIn ? "MainNavigator" : "LoginNavigator"
}
)
}
and I'm getting the error above. Since my Navigators depend on the variables created in construtor, I needed to do it via render(). Following react-native documentation on application containers didn't help.
In react-navigation v3, you must wrap makeRootNavigator with createAppContainer. Change your code to :
render() {
const Navigator = createAppContainer(makeRootNavigator(this.state.accessToken));
return <Navigator />
}
and don't forget to import createAppContainer on top of the file
import {createSwitchNavigator, createAppContainer} from 'react-navigation'
This is working solution for above problem
import { createStackNavigator } from 'react-navigation-stack'
import Login from './src/Login';
import Fruits from './src/Fruits';
import FruitZoom from './src/FruitZoom';
import {createAppContainer } from 'react-navigation';
import React from 'react';
const AppNavigator = createStackNavigator({
Login: { screen:Login},
Fruits: { screen: Fruits},
FruitZoom: { screen: FruitZoom}
}, {
initialRouteName: 'Login',
headerMode: 'none'
});
const Apps = createAppContainer(AppNavigator);
export default class App extends React.Component {
render() {
return <Apps />;
}
}

How to wrap redux store to my App.js in react native

import React from 'react';
import { View, Text } from 'react-native';
import { StackNavigator } from 'react-navigation';
import HomeScreen from './Home.js';
import EntryPoint from './src/containers/EntryPoint.js';
import Stage2 from './src/containers/Stage2.js';
const RootNavigator = StackNavigator({
Home: {
screen: HomeScreen,
navigationOptions: {
headerTitle: 'Material Management',
},
},
EntryPoint: {
screen: EntryPoint,
navigationOptions: {
headerTitle: 'Entry Point'
}
},
Stage2 : {
screen : Stage2,
navigationOptions : {
headerTitle : 'Stage 2'
}
}
});
export default RootNavigator;
The above code is my App.js
I want to wrap the redux store around it. How do i do that . Couldn't find a proper documentation for redux setup with React-native.
import { createStore,bindActionCreators } from 'redux'
import { connect, Provider } from 'react-redux'
function mapStateToProps(state) {
return state;
}
function mapDispatchToProps(dispatch) {
return bindActionCreators(Actions, dispatch);
}
let Container = connect(mapStateToProps,mapDispatchToProps)(RootNavigator);
export default class APP extends Component{
render(){
return (<Provider store={store}>
<Container/>
</Provider>)
}
};