React-native rendering button but not showing its height - reactjs

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.

Related

Show loading indicator between navigation of pages in a Webview

I have a url in the Webview like https://www.nytimes.com/ The current code works inital page load but If I type tap anything in the link, the page takes a while to load and there are no loading indicators in the website. Is there any way we can put a page loading indicator in React Native while we click on any link or page loading specially if it is server side rendered like next js?
Here is my ReactNative code.
import * as React from 'react';
import {
View,
Text,
Image,
SafeAreaView,
ScrollView,
TextInput,
TouchableOpacity,
} from 'react-native';
import styles from './styles';
import { WebView } from 'react-native-webview';
// import WelcomeSwiper from '../../components/WelcomeScreen/WelcomeSwiper';
import LoadingIcon from '../../components/Loading/index.js';
const WebView = ({ navigation }) => {
return (
<SafeAreaView style={styles.container}>
<WebView
javaScriptEnabled={true}
domStorageEnabled={true}
renderLoading={LoadingIcon}
source={{ uri: 'https://www.nytimes.com/ ' }}
startInLoadingState={true}
/>
</SafeAreaView>
);
};
export default WebView;
Here is my loading component
import React from 'react';
import { StyleSheet, Platform, ActivityIndicator } from 'react-native';
const LoadingIcon = () => {
return (
<ActivityIndicator
color='#009688'
size='large'
style={styles.ActivityIndicatorStyle}
/>
);
}
export default LoadingIcon;
const styles = StyleSheet.create(
{
WebViewStyle:
{
justifyContent: 'center',
alignItems: 'center',
flex: 1,
marginTop: (Platform.OS) === 'ios' ? 20 : 0
},
ActivityIndicatorStyle: {
position: 'absolute',
left: 0,
right: 0,
top: 0,
bottom: 0,
alignItems: 'center',
justifyContent: 'center'
}
});
we can use these two approaches to get the result:
You can check if the WebView is loading something or not with the onLoadProgress method. This method gives you a number between 0 and 1. If the page is fully loaded it will return number 1, update your state and show the ActivityIndicator according to it:
you can use onLoadStart and onLoadEnd to update your state and show the ActivityIndicator according to it!
for more info check the: https://github.com/react-native-community/react-native-webview/blob/master/docs/Reference.md#onloadprogress
you can also use your ActivityIndicator wrapped by WebView, *do not Forget this method works in ios for android put it outside of WebView
and this is a working code sample for you:
import React, {useState} from 'react';
import {View, Text, SafeAreaView, ActivityIndicator} from 'react-native';
import {WebView} from 'react-native-webview';
function WebViewTest() {
const [isLoading, setLoading] = useState(false);
return (
<SafeAreaView style={{flex: 1}}>
<WebView
source={{uri: 'https://www.nytimes.com/'}}
onLoadStart={(syntheticEvent) => {
setLoading(true);
}}
onLoadEnd={(syntheticEvent) => {
setLoading(false);
}} />
{isLoading && (
<View style={{flex: 10, backgroundColor: 'white'}}>
<ActivityIndicator
color="#009688"
size="large"
// style={{position: 'absolute', left: 200, top: 300}}
/>
</View>
)}
</SafeAreaView>
);
}
export default WebViewTest;
I hope it helps
I use onLoadProgress to solve this issue.
renderLoading function is just called at the initial loading state of webview component. Using renderLoading is not helpful to show activity indicators at any tap on page links or navigating between webview pages.
Checking onLoadStart and onLoadEnd is useful in android but in iOS onLoadEnd is not called in the back navigation gesture which results in endless spinning of activity indicator.
onLoadProgress returns a number between 0-1 while webview is in the loading state. You check its progress state and update your activity indicator state.
For more information about onLoadProgress: onLoadProgress
Here is a working code example for you:
import React, {useState} from 'react';
import {View, Text, SafeAreaView, ActivityIndicator} from 'react-native';
import {WebView} from 'react-native-webview';
function WebViewTest() {
const [isLoading, setLoading] = useState(false);
return (
<SafeAreaView style={{flex: 1}}>
<WebView
source={{uri: 'https://www.nytimes.com/'}}
onLoadProgress={({nativeEvent}) => {
if (nativeEvent.progress != 1 && isLoading == false ) {
setLoading(true)
} else if (nativeEvent.progress == 1 ) {
setLoading(false)
}
}}
/>
{isLoading && (
<View style={{flex: 10, backgroundColor: 'white'}}>
<ActivityIndicator
color="#009688"
size="large"
// style={{position: 'absolute', left: 200, top: 300}}
/>
</View>
)}
</SafeAreaView>
);
}
export default WebViewTest;

Is there a way to have a button render my camera component in React Native?

I am new to react native and am trying to make my camera component pop up whenever I click on a button. I am able to get the camera to render in App.js, but the minute I try to get it rendering in the component it just doesn't work. Should I use state to get this to render? If so, why doesn't react native allow you to just render a component within a component? I'm trying to understand the concept of components calling other components. Heres my code:
import React, {Component} from 'react';
import {Button, StyleSheet, Text, View} from 'react-native';
import DeviceCamera from './camera';
class CameraButton extends Component {
render() {
return (
<View style={styles.container}>
<Text> Button to Open Camera </Text>
<Button
onPress={() => {
<DeviceCamera />;
}}
title="click me to open the camera!"
color="#841584"
/>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: '#F5FCFF',
},
instructions: {
textAlign: 'center',
color: '#333333',
marginBottom: 5,
},
});
export default CameraButton;
I was trying to use the on press function to call the camera component but perhaps I am misunderstanding something.
Yeah, I would probably just use state here
class CameraButton extends Component {
showCamera = () => this.setState({ showCamera: true });
render() {
return (
<View style={styles.container}>
<Text> Button to Open Camera </Text>
<Button
onPress={this.showCamera}
title="click me to open the camera!"
color="#841584"
/>
{this.state.showCamera && <DeviceCamera />}
</View>
);
}
}
With JSX, you can use foo && <Bar />; if foo evaluates to something truthy, then it will render your component, otherwise it will not.

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,
}
});

How do I launch the RN Expo Camera in fullscreen from TouchableOpacity press?

I have a React Native Component that is conditionally rendering a TouchableOpacity "Camera" Icon upon initial screen load, and pressing this TouchableOpacity "Camera" Icon is intended to launch the Expo's React Native Camera which is housed in a separate component. I implemented logging to track my state and confirmed that the state is correctly updating thus launching the Expo Camera component.
The problem I'm having is that NO MATTER WHAT I TRY, I cant get the camera Capture window to render in fullscreen and instead renders somewhere off of the iOS simulator app window. AND when the camera is activated, I cant see the capture window but it's messing up all of my containers once the camera loads.
CameraLauncher.js (conditionally shows either a Camera icon or shows the NativeCamera component view.
import React, { Component } from 'react';
import { StyleSheet, TouchableOpacity, Modal, Text, View } from 'react-native';
import Icon from 'react-native-vector-icons/FontAwesome';
import { Camera } from 'expo';
import { NativeCamera } from './NativeCamera';
export class CameraLauncher extends Component {
constructor(props) {
super(props);
this.setCameraShowing = this.setCameraShowing.bind(this);
this.state = {
type: Camera.Constants.Type.back,
cameraOpen: false
}
}
setCameraShowing(){
this.setState({cameraOpen: true});
console.log('hi', this.state.cameraOpen)
}
render() {
const visible = this.state.cameraOpen
console.log('ho', this.state.cameraOpen)
if (visible) {
camera =
<NativeCamera style={StyleSheet.absoluteFill} />
} else {
camera =
<TouchableOpacity style={styles.cameraBtn} onPress={() => this.setCameraShowing(true)}>
<View>
<Icon
name="camera"
size={25}
color='#2196F3'
/>
</View>
</TouchableOpacity>
}
return (
<View>
{camera}
</View>
);
}
}
const styles = StyleSheet.create({
cameraBtn: {
color: '#2196F3',
marginTop: -15
}
});
NativeCamera.js (the actual camera window)
import React, { Component } from 'react';
import { Text, View, TouchableOpacity } from 'react-native';
import { Camera, Permissions } from 'expo';
export class NativeCamera extends Component {
constructor(props) {
super(props)
this.state = {
hasCameraPermission: null,
type: Camera.Constants.Type.back,
};
}
async componentWillMount() {
const { status } = await Permissions.askAsync(Permissions.CAMERA);
this.setState({ hasCameraPermission: status === 'granted' });
}
render() {
const { hasCameraPermission } = this.state;
if (hasCameraPermission === null) {
return <View />;
} else if (hasCameraPermission === false) {
return <Text>No access to camera</Text>;
} else {
return (
<View style={{ flex: 1 }}>
<Camera style={{ flex: 1 }} type={this.state.type}>
<View
style={{
flex: 1,
backgroundColor: 'transparent',
flexDirection: 'row',
}}>
<TouchableOpacity
style={{
flex: 0.1,
alignSelf: 'flex-end',
alignItems: 'center',
}}
onPress={() => {
this.setState({
type: this.state.type === Camera.Constants.Type.back
? Camera.Constants.Type.front
: Camera.Constants.Type.back,
});
}}>
<Text
style={{ fontSize: 18, marginBottom: 10, color: 'white' }}>
{' '}Flip{' '}
</Text>
</TouchableOpacity>
</View>
</Camera>
</View>
);
}
}
}
How do I make the Expo Camera capture window load over the entire screen? I was able to accomplish this with a <Modal /> by using presentationStyle='overFullScreen, but I don't know how to make that happen with the camera.
Also, yes I have already looked over this a million times and haven't found any examples of others using a button to launch the camera. https://docs.expo.io/versions/latest/sdk/camera/

getting null height for touchableOpacity

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

Resources