React Navigation drawer goes blank after adding contentComponent - reactjs

I am using React Navigation to create custom NavigationDrawer with a header on top this is how my code looks
import React, { Component } from "react";
import { View, Text, StyleSheet } from "react-native";
import AboutScreen from './modules/screens/About/index'
import ContactScreen from './modules/screens/Contact/index'
import HomeScreen from './modules/screens/Home/index'
import { createDrawerNavigator, DrawerItems } from "react-navigation";
import { Image, ScrollView, SafeAreaView, Dimensions } from 'react-native';
class NewDrawer extends Component {
render() {
return (
<AppDrawer />
);
}
}
const AppDrawer = createDrawerNavigator({
HomeScreen: HomeScreen,
AboutScreen: AboutScreen,
ContactScreen: ContactScreen,
},
//Commenting below part makes my code work
{
contentComponent: CustomDrawer
}
)
const CustomDrawer = (props) => (
<SafeAreaView style={{ flex: 1 }}>
<View style={{ height: 150, backgroundColor: 'white' }}>
<Image source={require('./modules/images/header.jpeg')}
style={{ height: 120, width: 120 }}>
</Image>
</View>
<ScrollView>
<DrawerItems {...props}>
</DrawerItems>
</ScrollView>
</SafeAreaView>
)
export default NewDrawer;
If I remove contentComponent i see my drawer items.
How can I get Header with custom drawer item?
I am using:-
npm > v6.4.1
Node > v8.12.0
react-navigation > v2.17.0
I am following this tutorial

You are not sending props to CustomDrawer . Try code below.
contentComponent: props => <CustomDrawer {...props} />

Drawer.js
<SafeAreaView style={{ flex: 1 }}>
<View style={{ height: 150, backgroundColor: 'white' }}>
<Image source={require('./modules/images/header.jpeg')}
style={{ height: 120, width: 120 }}>
</Image>
</View>
<ScrollView>
<DrawerItems {...props}>
</DrawerItems>
</ScrollView>
</SafeAreaView>
App.js
import CustomDrawer from './Drawer' // Import the file
const AppDrawer = createDrawerNavigator({
HomeScreen: HomeScreen,
AboutScreen: AboutScreen,
ContactScreen: ContactScreen,
},
{
contentComponent: <CustomDrawer />
}
)
This should work tested on android device

Related

React Native - React Navigation Cannot use Hooks in DrawerContent

I am developing an e-commerce application using React Native and I am trying to use useState in the drawerContent and it tells me this
Error: Invalid hook call. Hooks can only be called inside of the body
of a function component. This could happen for one of the following
reasons:
You might have mismatching versions of React and the renderer (such as React DOM)
You might be breaking the Rules of Hooks
You might have more than one copy of React in the same app
Thank you in advance for your answers.
Here's the code
import React, { useState } from 'react'
import { View, Text, TouchableOpacity, FlatList, StyleSheet, StatusBar } from 'react-native'
import IonIcons from "react-native-vector-icons/Ionicons"
import { categories } from '../../../services/DataTest'
import DrawerSearch from './DrawerSearch'
import DrawerItem from './DrawerItem'
export default function DrawerContent (props) {
const [search, setSearch] = useState("");
return (
<View>
<TouchableOpacity
style={styles.customDrawerTouch}
>
<View style={styles.backButtonRow}>
<IonIcons
name="ios-arrow-back"
size={25}
style={styles.customDrawerIcon}
color="#666666"
/>
<Text style={{ color: '#666666' }}>Back to Components</Text>
</View>
</TouchableOpacity>
<DrawerSearch value={search} setValue={setSearch}/>
<FlatList
data={categories}
keyExtractor={(item, index) => index.toString()}
renderItem={DrawerItem}
/>
</View>
);
}
const styles = StyleSheet.create({
customDrawerTouch: {
marginTop: StatusBar.currentHeight,
paddingLeft: 13,
paddingTop: 15,
},
customDrawerIcon: {
paddingRight: 10
},
backButtonRow: {
flexDirection: 'row',
alignItems: 'center',
paddingBottom: 17,
paddingLeft: 3,
borderBottomColor: '#F0F0F0',
borderBottomWidth: 1,
},
});
I'm using this component here
import * as React from 'react';
import { View, StyleSheet, StatusBar } from 'react-native';
import { createDrawerNavigator } from '#react-navigation/drawer';
import HeaderCategorie from '../../components/categories/index/HeaderCategorie';
import SearchBar from '../../components/home/index/SearchBar';
import DrawerContent from '../../components/categories/index/DrawerContent';
const Drawer = createDrawerNavigator();
function CategoriesScreen({ navigation }) {
return (
<View style={styles.container}>
<HeaderCategorie navigation={navigation}/>
<View style={styles.headerSearch}>
<SearchBar />
</View>
</View>
)
}
export default function Categories() {
return (
<Drawer.Navigator initialRouteName="Categories"
drawerContent={DrawerContent}
screenOptions={{headerShown:false}}
>
<Drawer.Screen name="Categories" component={CategoriesScreen} />
</Drawer.Navigator>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: "flex-start",
alignItems: "center",
marginTop: StatusBar.currentHeight,
},
headerSearch: {
marginVertical:10
},
headerSearchText: {
fontWeight:"bold",
fontSize:35,
marginLeft:20,
marginVertical:15,
}
});
Reason: By using drawerContent={DrawerContent}, you are actually passing the reference of the DrawerContent function, which ends up breaking rules of hooks.
So to resolve this, change the following line:
<Drawer.Navigator initialRouteName="Categories"
drawerContent={DrawerContent}
screenOptions={{headerShown:false}}
>
to this
<Drawer.Navigator initialRouteName="Categories"
drawerContent={(props)=> <DrawerContent {...props}/>} // here
screenOptions={{headerShown:false}}
>
demo snack

Too much space between the appbar and status bar

I am making an app, where I want to use react navigation.
For some reason, whenever I use drawers in react navigation, there is a huge space between the status bar and the drawer app bar.
Here is my code for the ho -
import { StatusBar } from "expo-status-bar";
import * as React from "react";
import { useState, useEffect } from "react";
import { StyleSheet, Text, View, ScrollView } from "react-native";
import Constants from "expo-constants";
import Header from "../Header";
import { Flexbox } from "../Layout";
import Card from "../Card";
import { marginAboveCard } from "../../constants/constants";
import Row from "../Row";
import { convertToIndianNumberingFormat } from "../../utils/utils";
const HomeScreen = ({ navigation }) => {
const [cardsData, setCardsData] = useState({
confirmed: 0,
active: 0,
recovered: 0,
deceased: 0,
tests: 0,
critical: 0,
});
const [lastUpdated, setLastUpdated] = useState("");
useEffect(() => {
const getData = async () => {
const cardsDataResponse = await fetch(
"https://disease.sh/v3/covid-19/all"
);
const cardsDataFetched = await cardsDataResponse.json();
setCardsData({
confirmed: convertToIndianNumberingFormat(
cardsDataFetched.cases
),
active: convertToIndianNumberingFormat(cardsDataFetched.active),
recovered: convertToIndianNumberingFormat(
cardsDataFetched.recovered
),
deceased: convertToIndianNumberingFormat(
cardsDataFetched.deaths
),
tests: convertToIndianNumberingFormat(cardsDataFetched.tests),
critical: convertToIndianNumberingFormat(
cardsDataFetched.critical
),
});
const time = new Date(cardsDataFetched.updated);
const lastupdated = time.toLocaleTimeString();
setLastUpdated(`Last updated at ${lastupdated}`);
};
getData();
}, []);
return (
<ScrollView style={styles.main}>
<View style={{ marginTop: Constants.statusBarHeight }}>
<StatusBar style="auto" />
<Header text="COVID-19" />
<Text style={styles.lastUpdatedText}>{lastUpdated}</Text>
<View style={{ marginTop: marginAboveCard }}>
<Flexbox style={{ marginTop: 15 }}>
<Card
background="red"
title="Confirmed"
number={cardsData.confirmed}
/>
<Card
background="#3877F0"
title="Active"
number={cardsData.active}
/>
</Flexbox>
<Flexbox style={{ marginTop: marginAboveCard }}>
<Card
background="#47CC3C"
title="Recovered"
number={cardsData.recovered}
/>
<Card
background="#868686"
title="Deceased"
number={cardsData.deceased}
/>
</Flexbox>
<Flexbox style={{ marginTop: marginAboveCard }}>
<Card
background="#E85FEB"
title="Tests"
number={cardsData.tests}
/>
<Card
background="#5BF8B6"
title="Critical"
number={cardsData.critical}
/>
</Flexbox>
</View>
<View style={{ marginTop: 30 }}>
<Header text="TABLE STATISTICS" />
</View>
</View>
</ScrollView>
);
};
export default HomeScreen;
const styles = StyleSheet.create({
main: {
flex: 1,
backgroundColor: "#000232",
},
lastUpdatedText: {
color: "white",
textAlign: "center",
marginTop: 12,
fontSize: 15,
},
});
My app.jsx -
import * as React from "react";
import HomeScreen from "./components/screens/HomeScreen";
import VaccineScreen from "./components/screens/VaccineScreen";
import { NavigationContainer } from "#react-navigation/native";
import { createDrawerNavigator } from "#react-navigation/drawer";
const Drawer = createDrawerNavigator();
export default function App() {
return (
<NavigationContainer>
<Drawer.Navigator initialRouteName="Home">
<Drawer.Screen name="Home" component={HomeScreen} />
<Drawer.Screen name="Vaccine" component={VaccineScreen} />
</Drawer.Navigator>
</NavigationContainer>
);
}
If you look at the code of home screen properly, you would see a status style component which is set to auto. Even after removing it, the space is there. There are no errors in the console of any sort. This error started coming when I used react navigation drawer. Is there a way I can remove the space?
Did you try to move StatusBar as top most child like my sample below?
....
<View>
<StatusBar style="auto" />
<ScrollView style={styles.main}>
<View style={{ marginTop: Constants.statusBarHeight }}>
...
How you define the header title and the drawer icon?

How to play a segment of a Lottie Animation (.json file ) in React Native

I want to play only a segment of the animation in react native using lottie view
the length is about 5 seconds while in speed={1} I wanna play only the first 3 seconds and then go to the next screen
the code is down below
LogoScreen.js :
import React from 'react';
import { StyleSheet, View, Image, TextInput, StatusBar, Text } from "react-native";
import Icons from 'react-native-vector-icons/Ionicons';
import LottieView from "lottie-react-native";
export default class ChatScreen extends React.Component {
onAnimationFinish = () => {
this.props.navigation.navigate("Login")
}
render () {
return (
<View style={styles.container}>
<StatusBar barStyle="light-content" backgroundColor="#161f3d" />
<View>
<LottieView
source={require('../assets/animations/lottie/MotionCorpse-Jrcanest.json')}
style={{ justifyContent: "center", alignSelf: "center", height: "100%", width: "100%" }}
autoPlay
loop={false}
speed={1}
onAnimationFinish={this.onAnimationFinish}
/>
</View>
</View>
)
}
Well you can do it by several ways, one of the way would be like below.
You can use ref to play it manually and then after 3 seconds just redirect to next screen.
import React from 'react';
import { StyleSheet, View, Image, TextInput, StatusBar, Text } from "react-native";
import Icons from 'react-native-vector-icons/Ionicons';
import LottieView from "lottie-react-native";
export default class ChatScreen extends React.Component {
componentDidMount() {
this.anim.play();
setTimeout(() => {
this.props.navigation.navigate("Login")
}, 3000);
}
render() {
return (
<View style={styles.container}>
<StatusBar barStyle="light-content" backgroundColor="#161f3d" />
<View>
<LottieView
source={require('../assets/animations/lottie/MotionCorpse-Jrcanest.json')}
style={{ justifyContent: "center", alignSelf: "center", height: "100%", width: "100%" }}
autoPlay={false}
loop={false}
speed={1}
ref={animation => { this.anim = animation; }}
/>
</View>
</View>
)
}
}
Another way is if you know exact frame numbers then you can play animation till that frame which completes at 3 seconds. It is already mentioned in Lottie documentation.
this.animation.play(30, 120);

export class on new files not working (react native)

I'm trying to build an app and it was working but for some reason now everytime I try to export something it no longer works (stays greyed out).
I have copy and pasted a page and just change the file name and the export class still stays greyed out.
I have deleted the node folder, cleared the cache, and reinstall the cache. Still won't work
Created a new file in the screen and component folder, copy pasted a working page (screen file to a screen file & component file to component file). The export class still stays greyed out.
example of a button component
import React, { Component } from 'react';
import {View, StyleSheet, Dimensions} from 'react-native';
export default function Timer(props) {
return(
<View style={styles.Button}>
<View>
{ props.children }
</View>
</View>
)
}
const styles = StyleSheet.create({
Button: {
height:31,
width: 87,
borderRadius: 10,
backgroundColor: '#E0F7EF',
display: 'flex',
justifyContent: 'center', /* center items vertically, in this case */
alignItems: 'center', /* center items horizontally, in this case */
},
})
Example of a screen component
import React, {Component} from 'react';
import * as firebase from 'firebase';
import { NavigationActions, StackNavigator } from 'react-navigation';
import{ ImageBackground, Dimensions, View, ScrollView, SafeAreaView, TextInput, Picker } from 'react-native';
import { SimpleLineIcons } from '#expo/vector-icons';
import { Container, Header, Content, Card, CardItem, Body, Text } from 'native-base';
import { MaterialCommunityIcons, FontAwesome, MaterialIcons, Ionicons} from '#expo/vector-icons';
import Strings from '../utils/Strings';
var styles = require('../../assets/files/Styles');
var {height, width} = Dimensions.get('window');
//NAVIGATION AT TOP
export default class Cardio extends Component {
static navigationOptions = {
title: `${Strings.ST201}`,
};
navigateToScreen = (route) => () => {
const navigateAction = NavigationActions.navigate({
routeName: route,
});
this.props.navigation.dispatch(navigateAction);
}
render () {
return (
<Container style={styles.background_general}>
<ScrollView>
<View style={{flexDirection:'column', backgroundColor: '#000000', height: height * 0.25}}>
<ImageBackground
source={require('../../assets/images/header.jpg')}
style={{flex: 1, width: null, height: null}}>
</ImageBackground>
</View>
<View style={styles.cardslayout}>
<TextInput
style={styles.CommentBox}
placeholder = 'sets'
returnKeyType="done"
/>
<TextInput
style={styles.CommentBox}
placeholder = 'Reps'
returnKeyType="done"
/>
</View>
<View>
<TextInput />
</View>
<View style={styles.cardslayout}>
<Content horizontal={true}>
{/*Bike*/}
<Card>
<CardItem style={styles.card}>
<Text>
<MaterialIcons name="directions-bike" size={32} color="white"/>
</Text>
</CardItem>
</Card>
<Card>
<CardItem style={styles.card}>
<Text>
<MaterialCommunityIcons name="run-fast" size={32} color="white"/>
</Text>
</CardItem>
</Card>
<Card>
<CardItem style={styles.card}>
<Text>
<Ionicons name="ios-walk" size={32} color="white"/>
</Text>
</CardItem>
</Card>
</Content>
</View>
{/*END OF CUSTOM INPUT*/}
</ScrollView>
</Container>
)
}
}
This is what I mean by it being grayed out.
This is a custom button file in the component folder.
You can see the export default function working in the custom button file. Now am going to create a test file and copy and paste the same code into it and simply change the function name. Now before I change the function name the "export default function" turns grey but I change the name to reduce confusion here.

use native base button with props

i want to create a reusable button component but i am having some issues. I get back undefined is not an onject evaluting '_nativebase.stylrsheetcreate'. I tried destructing the onPress and title but no luck. Can someone give a clear explanation on how to resolve this? thanks
import React from 'react';
import { View, Text, Button, StyleSheet } from 'native-base';
export const StyledButton = props => {
return (
<View style={styles.button}>
<Button
block
full
bordered
light
onPress={this.props.onPress}
>
<Text
style={{
color: '#FFFFFF',
}}
>
{this.props.title}
</Text>
{this.props.children}
</Button>
</View>
);
};
const styles = StyleSheet.create({
button: {
flex: 1,
padding: 10,
}
});
to Render
<StyledButton
title='Cancel'
onPress={this.somefunction}
/>
Remove this use props.someprop
import React from 'react';
import { StyleSheet } from 'react-native';
import { View, Text, Button } from 'native-base';
export const StyledButton = props => {
return (
<View style={styles.button}>
<Button block full bordered light onPress={props.onPress}>
<Text
style={{
color: '#FFFFFF',
}}>
{props.title}
</Text>
{props.children}
</Button>
</View>
);
};
const styles = StyleSheet.create({
button: {
flex: 1,
padding: 10,
}
});

Resources