getting null height for touchableOpacity - reactjs

Hi I am new to react native, I am following a course from udemy. In the course while creating a custom made button I am getting null height of the button but according to the course instructor the button should have height.
Below is the source code for App.js
import React, { Component } from 'react';
import { View, Text } from 'react-native';
import firebase from 'firebase';
import { Header, Button, Spinner } from './components/common';
import LoginForm from './components/LoginForm';
class App extends Component {
state = { loggedIn: null };
componentWillMount() {
firebase.initializeApp({
apiKey: 'AIzaSyB9AnPpTlaO5XbzPOhPPVBhCbn0SEel7hw',
authDomain: 'authentication-ce600.firebaseapp.com',
databaseURL: 'https://authentication-ce600.firebaseio.com',
projectId: 'authentication-ce600',
storageBucket: 'authentication-ce600.appspot.com',
messagingSenderId: '979192009377'
});
firebase.auth().onAuthStateChanged((user) => {
if (user){
this.setState({ loggedIn: true });
}
else{
this.setState({ loggedIn: false });
}
});
}
renderContent (){
switch (this.state.loggedIn) {
case true:
return (
<Button>
Log Out
</Button>
);
case false:
return <LoginForm />;
default:
return <Spinner size="large" />;
}
}
render (){
return (
<View>
<Header headerText="Auth"/>
{this.renderContent()}
</View>
);
}
};
export default App;
Below is the Button.js
import React from 'react';
import { Text, TouchableOpacity } from 'react-native';
const Button = ({onPress, children}) => {
return (
<TouchableOpacity onPress={onPress} style={styles.buttonStyle}>
<Text style={styles.textStyle}> {children} </Text>
</TouchableOpacity>
);
};
const styles = {
buttonStyle: {
flex: 1,
alignSelf: 'stretch',
backgroundColor: '#fff',
borderRadius: 5,
borderWidth: 1,
borderColor: '#007aff',
marginLeft: 5,
marginRight: 5
},
textStyle: {
fontSize: 16,
paddingTop: 10,
paddingBottom: 10,
color: '#007aff',
fontWeight: '600'
}
};
export {Button} ;
Here is what the expected output should be:
this is the actual ouput which I am getting:
Thanks in advance

This is because your <Header /> must have some height so it takes up all the space inside the parent <View></View> that's inside app.js. Now, since your <TouchableOpacity> inside button.js doesn't have any height (it only has flex). By just having flex it will take up the remaining available space and not take any height of it's own. There is no available space for it since the parent <View> in app.js doesn't have height of it's own. The parent <View>'s height will be equal to the height of the <Header>. There will be no available space for the Button.
For a quick fix, inside your button.js just give some height to buttonStyle like 200. You can also give it some width.
You can also apply a height (More than the header's height) to your parent <View> for this issue to go away.
Hope I've helped!

You can make slight change to Button.js to below
const Button = props => (
<TouchableOpacity onPress={props.onPress} style={styles.buttonStyle}>
<Text style={styles.textStyle}>{props.children}</Text>
</TouchableOpacity>
);
export default Button;
And in your App.js, you can pass those props as below to the Button component,
<Button
onPress={() => {
console.log('clicked');
}}
children={'Text Name'}
/>

import React, { Component } from 'react';
import { View } from 'react-native';
import firebase from 'firebase';
import { Header, Button, Spinner } from './components/common';
import LoginForm from './components/LoginForm';
class App extends Component {
state = { loggedIn: null };
componentWillMount (){
firebase.initializeApp({
apiKey: 'AIzaSyCnz8V-MuEiOWcs3oyBBxyO6BCjpAGJm7o',
authDomain: 'react-native-auth-284c7.firebaseapp.com',
databaseURL: 'https://react-native-auth-284c7.firebaseio.com',
storageBucket: 'react-native-auth-284c7.appspot.com',
messagingSenderId: '1049444233116'
});
firebase.auth().onAuthStateChanged((user) => {
if (user) {
this.setState({ loggedIn: true });
} else {
this.setState({ loggedIn: false });
}
});
}
renderContent() {
switch (this.state.loggedIn) {
case true:
return <View style={styles.buttonContainerStyle}>
<Button onPress={() => firebase.auth().signOut()}>
Log Out
</Button>
</View>;
case false:
return <LoginForm />;
default:
return <Spinner size="large" />;
}
}
render() {
return (
<View>
<Header headerText="Authentication" />
{this.renderContent()}
</View>
);
}
}
const styles = {
buttonContainerStyle: {
flexDirection: 'row',
height: 40
}
};
export default App;
Copied this code from https://github.com/csjcode/react-native-auth/blob/master/src/App.js .This code worked for me

Related

Accessing navigation parameters Expo-Go

I have got "Screen1" where I create a string "blabla". According to the documentation, I can set it as a navigation parameter:
export default function Screen1() {
const navigation = useNavigation();
navigation.navigate("Screen2", { item: "blalbla" });
return (
<View>
<Text>Render some stuff</Text>
</View>
);
}
On Screen2 I should be able to access it with:
export default function Screen2({ route, navigation }) {
const { item } = route.params;
console.log(item);
return (
<View>
<Text>Render some stuff</Text>
</View>
);
}
Now, this returns:
TypeError: undefined is not an object (evaluating 'route.params.item')]
I also tried some other examples without success.
Referring to React-Native documentation: https://reactnavigation.org/docs/params/
I've created a Snack. Check this out.
Follow below steps to solve your problem
Create a Folder called navigation where your App.js is located.
Then inside this folder create a file called AppNavigator.js
Inside AppNavigator.js paste this
import React from 'react';
import { View } from 'react-native';
import { createStackNavigator } from '#react-navigation/stack';
import Screen1 from '../screens/Screen1';
import Screen2 from '../screens/Screen2';
const Stack = createStackNavigator();
function AppNavigator() {
return (
<Stack.Navigator>
<Stack.Screen name="Screen1" component={Screen1} />
<Stack.Screen name="Screen2" component={Screen2} />
</Stack.Navigator>
);
}
export default AppNavigator;
Now create another folder called screens where your App.js is located
Inside this folder create your two files Screen1.js and Screen2.js
They should look like this
Screen1.js -
import React from 'react';
import { View, StyleSheet, Text, Button } from 'react-native';
function Screen1({ navigation }) {
return (
<View style={styles.container}>
<Text>Screen 1</Text>
<Text onPress={() => navigation.navigate('Screen2', { item: 'blalbla' })}>
Press ME
</Text>
</View>
);
}
export default Screen1;
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
},
});
Screen2.js -
import React from 'react';
import { View, StyleSheet, Text, Button } from 'react-native';
function Screen2({ route, navigation }) {
const { item } = route.params;
return (
<View style={styles.container}>
<Text>Screen 2</Text>
<Text onPress={() => navigation.navigate('Screen1')}>{item}</Text>
<Text onPress={() => navigation.navigate('Screen1')}>Press ME</Text>
</View>
);
}
export default Screen2;
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
},
});
Now you should see route parameters inside Screen2
navigation object is probably not present in the screen
change Screen1({ navigation }) to Screen1(props) and do console.log(props) to check if you see a navigation object there

Unexpected token, expected ";" in react native

I am a newbie in react native, I am developing a video app to aid my learning curve. In the code below I have tried all I could to solve the error on the "displayModal" line, but could not. Please can anyone help me with this.
I want on image/video capture it will display on the modal and from the modal i will be able to "Discard", or "Save"(to firebase), or "Share" the image/video.
import React from 'react';
import { View, Text, Image, Modal, TouchableOpacity } from 'react-native';
import { Ionicons } from '#expo/vector-icons';
import styles from './styles';
export default ({captures=[]}) => {
state = {
isVisible: false
}
// hide show modal
displayModal(show){ ------this is where am getting the error
this.setState({isVisible: show})
}
return (
<Modal
transparent={true}
visible={this.state.isVisible}
// style={[styles.bottomToolbar, styles.galleryContainer]}
>
<View style={{backgroundColor: "#000000aa", flex: 1}}>
{captures.map(({ uri }) => (
<View style={styles.galleryImageContainer} key={uri}>
<Image source={{ uri }} style={styles.galleryImage} />
</View>
))}
</View>
<TouchableOpacity style={{justifyContent: 'center', alignItems: 'center'}}>
<Ionicons
name="close-outline"
color="white"
size={20}
onPress={() => {this.displayModal(!this.state.isVisible);}}
/>
<Text>Discard</Text>
</TouchableOpacity>
</Modal>
);
};
click here to see error image
From you code it looks like a functional component, but you are using state as class-based component, that might be the reason you are getting error :
export default ({captures=[]}) => {
state = {
isVisible: false
}
// hide show modal
displayModal(show){ ------this is where am getting the error
this.setState({isVisible: show})
}
Above code block should look like this :
export default ({captures=[]}) => {
const [state,setState] = useState({ isVisible: false })
// hide show modal
const displayModal = (show) => {
setState({isVisible: show})
}
You are mixing functional component with class component.
"this.state" and "this.setState" belong to class components and all the rest belongs to functional components.
Try to change this:
state = {
isVisible: false
}
// hide show modal
displayModal(show){ ------this is where am getting the error
this.setState({isVisible: show})
}
To this:
const [isVisible, setIsVisible] = React.useState(false);
const displayModal = show => setIsVisible(show);
In addition, in the return statement, remove the strings/words "this" and "this.state".
Requested addition:
import React, { useState } from 'react';
import { View, Text, Image, Button, Modal, TouchableOpacity } from 'react-native';
import { Ionicons } from '#expo/vector-icons';
import { storage } from './fbstorage';
import { Camera } from 'expo-camera';
import styles from './styles';
export default ({ captures = [] }) => {
const [isVisible, setIsVisible] = useState(false);
const takePicture = async () => {
const photoData = await Camera.takePictureAsync();
if (!photoData.cancelled) {
uploadImage(photoData.uri, imageName)
.then(() => {
Alert.alert("Success");
})
.catch((error) => {
Alert.alert('Error:', error.message);
});
}
}
const uploadImage = async (uri, imageName) => {
const response = await fetch(uri);
const blob = await response.blob();
var ref = storage().ref().child("images/" + imageName);
return ref.put(blob)
}
return (
<Modal
transparent={true}
visible={isVisible}
// style={[styles.bottomToolbar, styles.galleryContainer]}
>
<View style={{ backgroundColor: "#000000aa", flex: 1 }}>
{captures.map(({ uri }) => (
<View style={styles.galleryImageContainer} key={uri}>
<Image source={{ uri }} style={styles.galleryImage} />
</View>
))}
</View>
<TouchableOpacity
style={{
justifyContent: 'center',
alignItems: 'center',
marginTop: 20,
top: -20
}}
onPress={() => setIsVisible(false)}
>
<Ionicons
name="md-reverse-camera"
color="white"
size={40}
/>
<Text style={{ color: 'white' }}>Discard</Text>
</TouchableOpacity>
<Button
title='Save'
onPress={takePicture}
/>
</Modal>
);
};

How to set the state from a button inside static navigationoption react-native?

I want to click the TouchableOpacity and set the state true so that will open. I am getting error. and how to align the button in center at the header? alignSelf is not working.
`
import React, {Component} from 'react';
import {
StyleSheet,
SafeAreaView,
View,
TouchableOpacity,
Text,
} from 'react-native';
import Menu from '../../src/components/menubar';
export default class SearchPage extends Component {
constructor(props) {
super(props);
this.state = {isMenubarDisplayed: false};
}
static navigationOptions = {
headerTitle: () => {
return (
<TouchableOpacity
onPress={()=> this.setState({isMenubarDisplayed: true})}>
<Icon name="search" size={20} color="#000" />
</TouchableOpacity>
);
},
headerTitleStyle: {
alignSelf: 'center',
flex: 1,
},
};
render() {
return (
<SafeAreaView style={styles.container}>
{this.state.isMenubarDisplayed ? (
<Menu />
) : null}
</SafeAreaView>
);
}
}`
You need to try this, expo-snack .
This is my below code for search.js ,
import * as React from 'react';
import { Text, View, StyleSheet,TouchableOpacity } from 'react-native';
import Constants from 'expo-constants';
import Menu from './menu';
import Icon from 'react-native-vector-icons/FontAwesome';
export default class Search extends React.Component {
constructor(props){
super(props);
this.state={
isMenubarDisplayed: false,
}
}
static navigationOptions = ({ navigation }) => {
return {
headerTitle: () => {
return (
<TouchableOpacity onPress={navigation.getParam('toggleMenu')}>
<Icon name="search" size={20} color="#000" />
</TouchableOpacity>
);
},
};
};
toggleMenu = () => {
this.setState({ isMenubarDisplayed: !this.state.isMenubarDisplayed})
}
renderMenu = () => (
<Menu />
)
componentDidMount(){
this.props.navigation.setParams({
toggleMenu: this.toggleMenu
});
}
render() {
return (
<View style={styles.container}>
{this.state.isMenubarDisplayed?this.renderMenu():<View></View>}
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
paddingTop: Constants.statusBarHeight,
backgroundColor: '#ecf0f1',
padding: 8,
},
});
Hope it helps. feel free for doubts.
This is all you need https://reactnavigation.org/docs/en/header-buttons.html#header-interaction-with-its-screen-component
static navigationOptions = ({ navigation }) => {
return {
headerTitle: () => {
return (
<View style={{ flex: 1, alignItems: 'center' }}>
<TouchableOpacity onPress={navigation.getParam('toggleMenu')}>
<Icon name="search" size={20} color="#000" />
</TouchableOpacity>
</View>
);
},
};
};
componentDidMount() {
this.props.navigation.setParams({ toggleMenu: this.toggleMenu });
}
toggleMenu = () => {
this.setState({isMenubarDisplayed: true});
}

React Native Navigation with React Native Admob About

I created a 3 page application with React native navigation. Admob ads are on the 3rd page. I want to try the same ad code on all three screens. If there is any idea in this matter, please share. Thank you.
For better understanding I give the following expo code.
import React, { Component } from 'react';
import {
WebView,
AppRegistry,
StyleSheet,
Text,
View,
Button,
Alert
} from 'react-native';
import { StackNavigator } from 'react-navigation';
import ListComponent from './ListComponent';
class App extends Component {
static navigationOptions = {
title: 'App',
};
OpenSecondActivityFunction = () => {
this.props.navigation.navigate('Second');
};
render() {
return (
<View style={styles.container}>
<Button
onPress={this.OpenSecondActivityFunction}
title="Open Second Activity"
/>
</View>
);
}
}
class SecondActivity extends Component {
static navigationOptions = {
title: 'SecondActivity',
};
OpenThirdActivityFunction = data => {
this.props.navigation.navigate('Third');
};
render() {
return (
<View style={{ flex: 1 }}>
<ListComponent
OpenThirdActivityFunction={this.OpenThirdActivityFunction}
/>
</View>
);
}
}
class ThirdActivity extends Component {
static navigationOptions = {
title: 'ThirdSecondActivity',
};
render() {
return (
<View style={{ flex: 1 }}>
<Text>3</Text>
</View>
);
}
}
const ActivityProject = StackNavigator({
First: { screen: App },
Second: { screen: SecondActivity },
Third: { screen: ThirdActivity },
});
export default ActivityProject;
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: '#F5FCFF',
}
});
Listcomponent.js
import React, { Component } from 'react';
import {
AppRegistry,
View,
Text,
FlatList,
ActivityIndicator,
} from 'react-native';
import { List, ListItem, SearchBar } from 'react-native-elements';
class ListComponents extends Component {
constructor(props) {
super(props);
this.state = {
loading: false,
data: [],
page: 1,
seed: 1,
error: null,
refreshing: false,
};
}
renderSeparator = () => {
return (
<View
style={{
height: 1,
width: '98%',
backgroundColor: '#CED0CE',
marginLeft: '2%',
}}
/>
);
};
renderHeader = () => {
return <SearchBar placeholder="Type Here..." lightTheme round />;
};
renderFooter = () => {
if (!this.state.loading) return null;
return (
<View
style={{
paddingVertical: 20,
borderTopWidth: 1,
borderColor: '#CED0CE',
}}>
<ActivityIndicator animating size="large" />
</View>
);
};
render() {
return (
<List containerStyle={{ borderTopWidth: 0, borderBottomWidth: 0 }}>
<FlatList
data={[{ name: 1, coders: 2 }]}
renderItem={({ item }) => (
<ListItem
roundAvatar
title={`${item.name}`}
subtitle={item.coders}
containerStyle={{ borderBottomWidth: 0 }}
onPress={() => this.props.OpenThirdActivityFunction(item.coders)}
/>
)}
keyExtractor={item => item.coders}
ItemSeparatorComponent={this.renderSeparator}
ListHeaderComponent={this.renderHeader}
ListFooterComponent={this.renderFooter}
/>
</List>
);
}
}
export default ListComponents;

React-native rendering button but not showing its height

I am trying to render logout button and its rendering it but its not showing height for the button. i am also adding the files which have data for Both button.js and app.js. now the problem is its showind button but the height of the button is 1 dont know why. i copied this code from somewhere and trying to make something out of it. some other place i am easily able to use button width. but not here.
and my common/index.js has all exported files like Button.js and all
getting button in this form.its showing but not with the size
Button.js
import React from 'react';
import { Text, TouchableOpacity } from 'react-native';
const Button = ({ onPress, children }) => {
const { buttonStyle, textStyle } = styles;
return (
<TouchableOpacity onPress={onPress} style={buttonStyle}>
<Text style={textStyle}>
{children}
</Text>
</TouchableOpacity>
);
};
const styles = {
textStyle: {
alignSelf: 'center',
color: '#007aff',
fontSize: 16,
fontWeight: '600',
paddingTop: 10,
paddingBottom: 10
},
buttonStyle: {
flex: 1,
alignSelf: 'stretch',
backgroundColor: '#fff',
borderRadius: 5,
borderWidth: 1,
borderColor: '#007aff',
marginLeft: 5,
marginRight: 5
}
};
export { Button };
App.js
import React, {Component} from 'react';
import { View } from 'react-native';
import firebase from 'firebase';
import { Header, Button, Spinner, Card } from './components/common';
import LoginForm from './components/LoginForm';
class App extends Component {
state = { loggedIn: null };
componentWillMount() {
firebase.initializeApp({
apiKey: '***********************************',
authDomain: '*********************************',
databaseURL: '***********************************',
projectId: '***************************************',
storageBucket: '*************************************',
messagingSenderId: '32810678085'
});
firebase.auth().onAuthStateChanged((user) => {
if(user){
this.setState({ loggedIn: true });
}else {
this.setState({ loggedIn: false });
}
});
}
renderContent(){
switch (this.state.loggedIn){
case true:
return <Button> Log out </Button>
case false:
return <LoginForm />;
default:
return <Spinner size="large" />;
}
}
render() {
return (
<View>
<Header headerText="Authentication" />
{this.renderContent()}
</View>
)
}
}
export default App;
I've had the exact same problem.
First of all, the version of React Native in the tutorial was different to the version that you used judging by the date of the post, this could point to a possible explanation of why the code worked in the tutorial but not in our code, although I can't know.
On the other side, it's not exactly true that the button code works in other
parts of the code.
When you render the login form, the button is enclosed in a CardSection component.
<Card>
...
<CardSection>
{this.renderButton()}
</CardSection>
</Card>
The CardSection component defines the flexDirection of its children as
'row' (horizontal) and the flex property of the Button "flex: 1" expands the width of the button along the horizontal (row) axis of its parent.
So, to make that code work in current versions of react-native, you have two options:
1.- Enclose the logout button in a CardSection:
import { Header, Button, CardSection } from './components/common';
renderContent() {
if (this.state.loggedIn) {
return (
<CardSection>
<Button>Log Out</Button>
</CardSection>
);
}
return <LoginForm />;
}
2.- Enclose the button in a View and give it at least a style property of "flexDirection: row":
renderContent() {
if (this.state.loggedIn) {
return (
<View style={style.containerStyle}>
<Button>Log Out</Button>
</View>
);
}
return <LoginForm />;
}
const style = {
containerStyle: {
flexDirection: 'row',
}
};
Usually you should wrap your TouchableOpacity sections in Views, they respond much better to styling. When learning react-native i often ran into a similar error.
I like to structure my implementation of buttons like so:
//Note i have edited this to tie in with your code
//
//Button.js file
//
//
return (
<View style = {buttonStyle}>
<TouchableOpacity onPress={onPress}>
<Text style={textStyle}>
{children}
</Text>
</TouchableOpacity>
</View>);
EDIT: Now, you should be able to add a height component to the buttonStyle, and then the button should display as you expect :-) Pseudo code:
//Other styling components...
height: 50,
//Other styling components...
Just add this:
marginTop:5
to the buttonStyle object.

Resources