React Native: React Navigation using reusable component - react-native

I'am new in React Native & I'am trying to create separated Button component file (reusable component), and when I press the button it will navigate to another page (react-navigation). Below is my code:
GlobalButton.js
import React from 'react'
import { StyleSheet, TouchableOpacity, Text} from 'react-native'
import { useNavigation, NavigationContainer } from '#react-navigation/native';
const GlobalButton = (props, {screenName}) => {
const navigation = useNavigation();
return
<TouchableOpacity style={[styles.btn, props.style]} onPress= {() => navigation.navigate(screenName)}>
{props.children}
</TouchableOpacity>
}
const styles = StyleSheet.create({
btn: {
alignItems: 'center',
textAlign: 'center',
borderRadius: 25,
height: 50,
}
})
export default GlobalButton;
LoginPage.js
import React from 'react'
import { StyleSheet, Text, View, Image, TextInput, Button} from 'react-native'
import ButtonLogin from '../components/GlobalButton'
// import { useNavigation, NavigationContainer } from '#react-navigation/native';
export default function LoginPage() {
return (
<View style={styles.penampung}>
<Image source= {require('../assets/beetle.png')} style={styles.gambar}/>
<TextInput style={styles.textField} placeholder='username' />
<TextInput style={styles.textField} placeholder='password' secureTextEntry={true} />
<ButtonLogin style={styles.btnStyle} screenName="MainPage"><Text style={styles.text}>LOGIN</Text></ButtonLogin>
</View>
)
}
const styles = StyleSheet.create({
penampung: {
flex: 1,
alignItems: 'center',
backgroundColor: '#00688B',
justifyContent: 'center'
},
gambar: {
height: 100,
width: 100,
},
textField: {
marginTop: 25,
backgroundColor: '#cafafe',
borderRadius: 25,
width: '80%',
height: 50,
paddingLeft: 20
},
btnStyle: {
padding: 10,
position: 'absolute',
bottom: 20,
backgroundColor: "#fc4445",
width: '80%'
},
text:{
fontSize: 20,
fontWeight: 'bold',
color: 'white'
}
})
What I'am expecting is that when I click the login button it should navigate to the MainPage.js, but instead it gives error message ->
Error: You need to specify name or key when calling navigate with an object as the argument.
Please anyone help me in this matter, Thanks...

You should do like below as screenName is part of your props,
<TouchableOpacity style={[styles.btn, props.style]} onPress= {() => navigation.navigate(props.screenName)}>

Related

Text strings must be rendered within a <Text> component. When creating a button

I'm new to react native and trying to create a button, here is my StartScreen:
import React from 'react' import Background from '../components/Background' import AppButton from '../components/AppButton'
export default function StartScreen({ navigation }) {
return(
<Background>
<AppButton title="HEEEY!" size="sm" backgroundColor="#007bff" />;
</Background>
) }
Here is my AppButton:
import React from 'react'
import { StyleSheet, TouchableOpacity, Text } from "react-native";
export default function AppButton ({ onPress, title, size, backgroundColor }) {
return (
<TouchableOpacity
onPress={onPress}
style={[
styles.appButtonContainer,
size === "sm" && {
paddingHorizontal: 8,
paddingVertical: 6,
elevation: 6
},
backgroundColor && { backgroundColor }
]}
>
<Text style={[styles.appButtonText, size === "sm" && { fontSize: 14 }]}>
{title}
</Text>
</TouchableOpacity>
)
};
const styles = StyleSheet.create({
screenContainer: {
flex: 1,
justifyContent: "center",
padding: 16
},
appButtonContainer: {
elevation: 8,
backgroundColor: "#009688",
borderRadius: 10,
paddingVertical: 10,
paddingHorizontal: 12
},
appButtonText: {
fontSize: 18,
color: "#fff",
fontWeight: "bold",
alignSelf: "center",
textTransform: "uppercase"
}
});
Here is my Background:
import React from 'react'
import { ImageBackground, StyleSheet, KeyboardAvoidingView } from 'react-native'
import { theme } from '../core/theme'
export default function Background({ children }) {
return (
<ImageBackground style={styles.background}>
<KeyboardAvoidingView style={styles.container} behavior="padding">
{children}
</KeyboardAvoidingView>
</ImageBackground>
)
}
const styles = StyleSheet.create({
background: {
flex: 1,
width: '100%',
backgroundColor: theme.colors.surface,
},
container: {
flex: 1,
padding: 20,
width: '100%',
maxWidth: 340,
alignSelf: 'center',
alignItems: 'center',
justifyContent: 'center',
},
})
When I try to run the application in my Android phone I get the following error:
Error: Text strings must be rendered within a component.
Blockquote
But I cant figure out where this error happens. Can someone spot the mistake?
You have an unnecessary semicolon (;) in your StartScreen JSX, remove it.
export default function StartScreen({ navigation }) {
return(
<Background>
<AppButton title="HEEEY!" size="sm" backgroundColor="#007bff" />
</Background>
); }

Why is my style not applied to my child component?

Good evening,
I have been trying to create custom card Component in react native that i can use everywhere i need it.
I apply a part of the style inside the component itself, and for the width, layout etc, where i need it. Then i am trying to use the spread operator to "merge" all the properties in the style of the child component. I saw it in a video tutorial, but it's not working for me, and i don't see what is wrong in my code :
import React from 'react';
import { View, Text, StyleSheet, TextInput, Button } from 'react-native';
import Card from '../components/Card';
import Color from '../constants/colors'
import Input from '../components/Input'
const StartGameScreen = props => {
return (
<View style={styles.screen}>
<Text style={styles.title}>Start a New Game!</Text>
<Card style={styles.inputContainer}>
<Text>Select a Number</Text>
<Input />
<View style={styles.buttonContainer}>
<Button title="Reset" color={Color.accent} onPress={() => {}} />
<Button title="Confirm" color={Color.primary} onPress={() => {}} />
</View>
</Card>
</View>
);
};
const styles = StyleSheet.create({
screen: {
flex: 1,
padding: 10,
alignItems: 'center'
},
title: {
fontSize: 20,
marginVertical: 10
},
inputContainer: {
width: 300,
maxWidth: '80%',
alignItems: 'center',
},
buttonContainer: {
flexDirection: 'row',
width: '100%',
justifyContent: 'space-between',
paddingHorizontal: 15
},
input: {
width: 50
}
});
export default StartGameScreen;
And the child component :
import React from 'react';
import { View, StyleSheet } from 'react-native';
const Card = props => {
return (
<View style={{ ...styles.card, ...props.style }}> {props.children}</View>
);
};
const styles = StyleSheet.create({
card: {
shadowColor: 'black',
shadowOffset: { width: 0, height: 2 },
shadowRadius: 6,
shadowOpacity: 0.26,
elevation: 8,
backgroundColor: 'white',
padding: 20,
borderRadius: 10
}
});
export default Card;
Note : I tried with input and card, it's working for none of them.
Is that something that we were able to do but we can't anymore ?
Thank you
Have a nice weekend
Try this:
const Card = props => {
return (
<View style={[styles.card, props.style ]}> {props.children}</View>
);
};

ScrollView removing TextInput keyboard in React Native

I am using TextInput with custom clear icon to clear text. As I need to keep multiple TextInputs in screen, I used a ScrollView:
import React, {Component} from 'react';
import {
View,
Text,
ScrollView,
StyleSheet,
Image,
TouchableOpacity,
TextInput,
} from 'react-native';
export default class SuccessScreen extends Component {
constructor(props) {
super(props);
this.state = {};
}
handleRightClick() {
console.log('handleRightClick');
}
render() {
return (
<ScrollView>
<View style={styles.SectionStyle}>
<TextInput style={styles.input} />
<TouchableOpacity
style={styles.ImageStyle}
onPress={this.handleRightClick}>
<Image source={require('../../images/cross_icon.png')} />
</TouchableOpacity>
</View>
</ScrollView>
);
}
}
const styles = StyleSheet.create({
input: {
flex: 1,
borderColor: '#000000',
borderBottomWidth: 1,
height: 40,
fontSize: 15,
color: '#000000',
},
SectionStyle: {
flexDirection: 'row',
minWidth: '100%',
height: 40,
},
ImageStyle: {
height: 25,
width: 25,
marginLeft: -25,
alignContent: 'center',
resizeMode: 'stretch',
alignItems: 'center',
},
});
Without the ScrollView, handleRightClick is called, but when I use the ScrollView, it just dismiss keyboard and don't call handleRightClick.
The ScrollView has a prop keyboardShouldPersistTaps. You should set it to 'handled' so your TouchableOpacity will handle the press instead of the ScrollView.
<ScrollView keyboardShouldPersistTaps='handled'>
// ...
</ScrollView>

React Native Reusable Card Component won't Visualize as expected

Hello there I'm new to react native. I'm trying to create reusable component, not only card component, maybe in future will create other reusable components. Below is the code example of reusable card component that I've created:
Card.js
import React from 'react';
import { View, StyleSheet } from 'react-native';
const Card = props => {
return (
<View style={{...styles.card, ...props.style}}>{props.children}</View>);};
const styles = StyleSheet.create({
card: {
shadowColor: 'black',
shadowOffset: { width: 0, height: 2 },
shadowRadius: 6,
shadowOpacity: 0.26,
elevation: 8,
backgroundColor: 'white',
padding: 20,
borderRadius: 10,
}
});
export default Card;
StartGameScreen.js
import React from 'react';
import { View, Text, StyleSheet, TextInput, Button } from 'react-native';
import Card from '../components/Card';
const StartGameScreen = props => {
return (
<View style={styles.screen}>
<Text style={styles.title}>Start a New Game!</Text>
<Card style={styles.inputContainer}>
<Text>Select a Number</Text>
<TextInput />
<View style={styles.buttonContainer}>
<View style={styles.button}><Button title="Reset" onPress={() => {}} /></View>
<View style={styles.button}><Button title="Confirm" onPress={() => {}} /></View>
</View>
</Card>
</View>
);
};
const styles = StyleSheet.create({
screen: {
flex: 1,
padding: 10,
alignItems: 'center'
},
title: {
fontSize: 20,
marginVertical: 10
},
inputContainer: {
width: 300,
maxWidth: '80%',
alignItems: 'center'
},
buttonContainer: {
flexDirection: 'row',
width: '100%',
justifyContent: 'space-between',
paddingHorizontal: 15
},
button: {
width:100
}
});
export default StartGameScreen;
The Result as below:
I'm expecting it to be as below:
Is it possible to use my above code and have the expected result? or is my code wrong and there is better solution??
Your card component is reusable only mistake is the way you are merging the styles. When you merge styles you should not expand it but use an array of styles. Like below.
const Card = props => {
return (<View style={[styles.card, props.style]}>{props.children}</View>);
};
You can check the below snack for full code.
https://snack.expo.io/#guruparan/e368b9

Text wrap with chevron on right in React Native ListView item renderer

I am trying to have a list view show up that looks similar to this. The problem I am trying to solve is regarding word wrapping of the label. I do have it working with the code below, but it feels like a hack and doesn't work with device rotation. There has to be a way to do it without using Dimensions and styling.
Here is what I have.
import React, { Component } from 'react';
import {
StyleSheet,
Dimensions,
TouchableOpacity,
Text,
View
} from 'react-native';
import Moment from 'moment'
import Icon from 'react-native-vector-icons/FontAwesome';
class ProjectListItemRenderer extends Component {
componentDidMount() {
//alert(Dimensions.get('window').height)
}
render() {
return (
<View style={styles.projectRow}>
<View style={{width: Dimensions.get('window').width - 50}}>
<Text style={styles.itemName}>{this.props.name}</Text>
<Text style={styles.itemDetails}>{`${Moment(this.props.lastUpdated).fromNow()}`}</Text>
</View>
<View style={styles.moreContainer}>
<Icon name="chevron-right" size={15} style={styles.moreIcon} />
</View>
</View>
);
}
}
const styles = StyleSheet.create({
projectRow: {
flexDirection: 'row',
justifyContent: 'flex-start',
padding: 15,
},
itemName: {
fontSize: 18,
color: '#4A90E2',
},
itemDetails: {
fontSize: 12,
color: '#BBBBBB',
},
moreContainer: {
justifyContent: 'center',
alignItems: 'center'
},
moreIcon: {
color: "#d6d7da"
}
});
module.exports = ProjectListItemRenderer;
The other option I tried was absolute positioning, with the label being 20px from the right, and then absolute positioning the chevron on the right. The problem I ran into there was trying to figure out the height of the individual listItem renderer after it is rendered (and word wrapped).
The problem comes from having flexDirection: 'row' in the View containing your text. This makes the text overflow to the right instead of wrapping. If you want your text to wrap, the containing View must have flexDirection: 'column' in the style.
I've modified your code accordingly:
import React, { Component } from 'react';
import {
StyleSheet,
Dimensions,
TouchableOpacity,
Text,
View
} from 'react-native';
import Moment from 'moment'
import Icon from 'react-native-vector-icons/FontAwesome';
class ProjectListItemRenderer extends Component {
componentDidMount() {
//alert(Dimensions.get('window').height)
}
render() {
return (
<View style={styles.projectRow}>
<View style={styles.projectText}>
<Text style={styles.itemName}>{this.props.name}</Text>
<Text style={styles.itemDetails>
{`${Moment(this.props.lastUpdated).fromNow()}`}
</Text>
</View>
<View style={styles.moreContainer}>
<Icon name="chevron-right" size={15} style={styles.moreIcon} />
</View>
</View>
);
}
}
const styles = StyleSheet.create({
projectText: {
flex: 1,
flexDirection: 'column'
},
projectRow: {
flexDirection: 'row',
justifyContent: 'flex-start',
padding: 15,
},
itemName: {
fontSize: 18,
color: '#4A90E2',
},
itemDetails: {
fontSize: 12,
color: '#BBBBBB',
},
moreContainer: {
justifyContent: 'center',
alignItems: 'center'
},
moreIcon: {
color: "#d6d7da"
}
});
module.exports = ProjectListItemRenderer;
The only difference is I replaced {width: Dimensions.get('window').width - 50} with {flex: 1, flexDirection: 'column'}.