This is driving me insane and I can't spot the issue. I'm trying to conditionally render an image component but it's throwing Invariant Violation: Text strings must be rendered within a <Text> component. Not even using a text string where the statement is.
render() {
return (
<View style={newsItemStyles.wrapper}>
{this.state.isLoading && (
<View style={loadingOverlayStyles.container}>
<ActivityIndicator />
<StatusBar barStyle="default" />
</View>
)}
{this.props.item.uri && ( // this is there the error is thrown
<View>
<Image
style={{width: '100%', height: 250}}
source={{uri: this.props.item.uri}}
/>
</View>
)}
<TouchableHighlight
onPress={() =>
this.props.navigation.navigate('NewsSingle', {
item: this.props.item,
title: this.props.item.title,
favorite: this.props.favorite,
})
}>
<Text numberOfLines={2}>{this.props.item.title}</Text>
</TouchableHighlight>
{this.props.favorite ? (
<TouchableOpacity activeOpacity={0.5} onPress={this.unfavorite}>
<FontAwesome5 name="bookmark" size={18} solid />
</TouchableOpacity>
) : (
<TouchableOpacity activeOpacity={0.5} onPress={this.favorite}>
<FontAwesome5 name="bookmark" size={18} />
</TouchableOpacity>
)}
</View>
);
}
Error is simple. You have to be careful when rendering components like:
someCondition && <someComponent />
Because there are some values that JSX will render as a text. An example of this, 0, this is a falsy value that JSX won't render as a boolean.
To fix this you just have to use the double negation operator to get the appropriate boolean value just like:
{!!this.props.item.uri && ( // error won't throw
<View>
<Image
style={{width: '100%', height: 250}}
source={{uri: this.props.item.uri}}
/>
</View>
)}
Ill modularize the code and issue should be solved otherwise letme know:
returnImage = () => (<View>
<Image
style={{width: '100%', height: 250}}
source={{uri: this.props.item.uri}}
/>
</View>)
displayImage = () => {
let renderData = this.props.item.uri ? this.returnImage():null
}
render() {
return (
<View style={newsItemStyles.wrapper}>
{this.state.isLoading && (
<View style={loadingOverlayStyles.container}>
<ActivityIndicator />
<StatusBar barStyle="default" />
</View>
)}
{}
<TouchableHighlight
onPress={() =>
this.props.navigation.navigate('NewsSingle', {
item: this.props.item,
title: this.props.item.title,
favorite: this.props.favorite,
})
}>
<Text numberOfLines={2}>{this.props.item.title}</Text>
</TouchableHighlight>
{this.props.favorite ? (
<TouchableOpacity activeOpacity={0.5} onPress={this.unfavorite}>
<FontAwesome5 name="bookmark" size={18} solid />
</TouchableOpacity>
) : (
<TouchableOpacity activeOpacity={0.5} onPress={this.favorite}>
<FontAwesome5 name="bookmark" size={18} />
</TouchableOpacity>
)}
</View>
);
}
hope it helps
Related
I'm currently making a registration form using React Native. When I implement into the application, a scroll bar doesn't work.
return (
<TouchableWithoutFeedback
onPress={() => {
Keyboard.dismiss();
}}>
<View style={styles.container}>
<ScrollView>
<View style={styles.formContainer}>
<View style={styles.registerTextContainer}>
{/* <Text style={styles.registerText}>Register for an account</Text> */}
</View>
<Form type={User} ref={c => (this._form = c)} options={options} />
<TouchableOpacity
style={styles.registerButtonContainer}
onPress={this.handleSubmit}>
<Text style={styles.registerButtonText}>REGISTER</Text>
</TouchableOpacity>
</View>
</ScrollView>
</View>
</TouchableWithoutFeedback>
);
}
This is how the application currently looks
Trying wrapping the whole page with ScrollView instead of TouchableWithoutFeedback and set flex to 1
return (
<ScrollView style={{ flex: 1 }}>
<TouchableWithoutFeedback
onPress={() => {
Keyboard.dismiss();
}}
>
<View style={styles.container}>
<View style={styles.formContainer}>
<View style={styles.registerTextContainer}>
{/* <Text style={styles.registerText}>Register for an account</Text> */}
</View>
<Form type={User} ref={(c) => (this._form = c)} options={options} />
<TouchableOpacity
style={styles.registerButtonContainer}
onPress={this.handleSubmit}
>
<Text style={styles.registerButtonText}>REGISTER</Text>
</TouchableOpacity>
</View>
</View>
</TouchableWithoutFeedback>
</ScrollView>
);
Don't set flex:1 in scroll view, instead try
<ScrollView contentContainerStyle={{ flexGrow: 1}}>
I don't have any idea what's wrong with this code.
I use react navigation, and it was working perfectly, but I got an error out of nowhere.
I think something is wrong with the nav
Here is Github Repo
So this is Home.js
const Home = ({ navigation }) => {
return (
<>
<ImageBackground source={require('../images/wall.jpeg')} style={styles.back}>
<View style={styles.box}>
<Image source={require('../images/logo.png')} style={styles.logo}/>
<TouchableOpacity onPress={() => navigation.navigate('Questions')}>
<View style={styles.container}
>
<Image source={require('../images/game.png')} style={styles.icons}/>
<Text style={{fontFamily: 'bpg_extrasquare_mtavruli_2009', fontSize: 20}}>გასართობი</Text>
</View>
</TouchableOpacity>
<TouchableOpacity onPress={() => navigation.navigate('Questions')}>
<View style={styles.container2}>
<Text style={{fontFamily: 'bpg_extrasquare_mtavruli_2009', fontSize: 20}}>ცენზურა</Text>
<Image source={require('../images/hand.png')} style={styles.icons}/>
</View>
</TouchableOpacity>
<TouchableOpacity onPress={() => navigation.navigate('Questions')}>
<View style={styles.container3}>
<Image source={require('../images/gender.png')} style={styles.icons}/>
<Text style={{fontFamily: 'bpg_extrasquare_mtavruli_2009', fontSize: 20}}></Text>
</View>
</TouchableOpacity>
</View>
</ImageBackground>
</>
);
};
const Stack = createStackNavigator();
function MyStack() {
return (
<Stack.Navigator
>
<Stack.Screen name="Home" component={Home} />
<Stack.Screen name="Questions" component={Questions} />
</Stack.Navigator>
);
}
So if you have any idea what's wrong please help
You can clear cache and kill allnode, or there is something wrong with the code
I am new to react-native. I am trying to use props and navigation in a const function. I do not know how to do that.
render() {
return (
<View style={styles.container}>
{this.state.signedIn ? (
<LoggedInPage name={this.state.name} photoUrl={this.state.photoUrl} />
) : (
<LoginPage signIn={this.signIn} />
)}
<TouchableOpacity
onPress={() => {this.props.navigation.navigate('About You')}}
style={styles.submitButton4}>
<Text style={styles.buttonText2}> Next </Text>
</TouchableOpacity>
</View>
);
}
const LoggedInPage = props => {
return (
Welcome {props.name}
<Image style={styles.image} source={{ uri: props.photoUrl }} />
Change photo
<TouchableOpacity
onPress={() => {this.props.navigation.navigate('registration')}}
style={styles.submitButton4}>
Next
)
}
if your LoggedInPage is one of the screens defined in the Navigator, then the navigation prop is automatically passed into your component. you can then use navigation like so props.navigation.navigate
all you need is pass in the navigation prop from your parent.
return (
<View style={styles.container}>
{this.state.signedIn ? (
<LoggedInPage name={this.state.name} photoUrl={this.state.photoUrl} navigation={this.props.navigation} />
) : (
<LoginPage signIn={this.signIn} navigation={this.props.navigation} />
)}
<TouchableOpacity
onPress={() => {this.props.navigation.navigate('About You')}}
style={styles.submitButton4}>
<Text style={styles.buttonText2}> Next </Text>
</TouchableOpacity>
</View>
);
then you can use it the name way:
const LoggedInPage = props => {
return (
<Text style={styles.text1}>Welcome {props.name}</Text>
<Image style={styles.image} source={{ uri: props.photoUrl }} />
<TouchableOpacity
style={styles.submitButton1}>
<Text style={styles.buttonText3}> Change photo </Text>
</TouchableOpacity>
<TouchableOpacity
onPress={() => {props.navigation.navigate('registration')}}
style={styles.submitButton4}>
<Text style={styles.buttonText2}> Next </Text>
</TouchableOpacity>
</View>
) }
I am trying to toggle a Modal in react native. Each item in a flatlist should have a toggle option to open a modal.
I get the error:
JSX expressions must have one parent element.
I have tried to google for the right syntax but can't find a solution.
class CategoriesScreen extends Component {
state = {
modalVisible: false,
};
setModalVisible(visible) {
this.setState({ modalVisible: visible });
}
render() {
function Item({ title }) {
return (
<TouchableOpacity style={styles.item} onPress={() => {
this.setModalVisible(true);
}}>
<View>
<Text style={styles.title}>{title}</Text>
</View>
</TouchableOpacity>
<Modal
animationType="slide"
transparent={false}
visible={this.state.modalVisible}
onRequestClose={() => {
Alert.alert('Modal has been closed.');
}}>
<View style={{ marginTop: 22 }}>
<View>
<Text>Hello World!</Text>
<TouchableOpacity
onPress={() => {
this.setModalVisible(!this.state.modalVisible);
}}>
<Text>Hide Modal</Text>
</TouchableOpacity>
</View>
</View>
</Modal>
};
return (
<SafeAreaView style={styles.container}>
<Text style={styles.heading}>Select a category for daily tasks.</Text>
<Text style={styles.subheading}>{`You will receive a daily task in this category.\nLet’s get consistent!`}</Text>
<FlatList
data={DATA}
renderItem={({ item }) => <Item title={item.title} />}
keyExtractor={item => item.id}
numColumns={2}
/>
</SafeAreaView>
);
}
}
I am trying to get open one unique modal for each item in the flatlist.
You can only return a single entity. To fix this just surround your return in your Item function with a <Fragment/> element (from the react package).
Fragments let you group a list of children without adding extra nodes to the DOM.
This can be done like so:
import React, {Fragment} from 'react';
...
function Item({ title }) {
return (
<Fragment>
<TouchableOpacity style={styles.item} onPress={() => {
this.setModalVisible(true);
}}>
<View>
<Text style={styles.title}>{title}</Text>
</View>
</TouchableOpacity>
<Modal
animationType="slide"
transparent={false}
visible={this.state.modalVisible}
onRequestClose={() => {
Alert.alert('Modal has been closed.');
}}>
<View style={{ marginTop: 22 }}>
<View>
<Text>Hello World!</Text>
<TouchableOpacity
onPress={() => {
this.setModalVisible(!this.state.modalVisible);
}}>
<Text>Hide Modal</Text>
</TouchableOpacity>
</View>
</View>
</Modal>
</Fragment>
)
};
Hope this helps,
The data is coming dynamically and I want to change state of bookmark icon individually. When we click on first box then only change state of bookmark of that box only others will remain as it is.
My code
this.state={ isTagged: false };
_handle_tag_btn() {
if(this.state.isTagged == true) {
this.setState({isTagged: false})
}
else {
this.setState({isTagged: true})
}
}
render(){
return(
<View style={{flex: 1}}>
{
this.state.product_detail.length <= 0 ?
<ActivityIndicator color = '#bc2b78' size = "large" />
:
<View style={{flexDirection: 'row', flexWrap: 'wrap'}}>
{
this.state.product_detail.map((data, index) => (
<View style={s.cate_detail_box}>
<TouchableOpacity activeOpacity={0.9} style={{height: 190}} onPress={this._goto_individual_detail}>
<Image source={{uri: data.images[0].src}} style={s.img}/>
</TouchableOpacity>
<View style={{padding: 5}}>
<View activeOpacity={0.9} style={{flexDirection: 'row', justifyContent: 'space-between'}}>
<View>
<CapitalizedText style={s.cate_detail_title}>{data.title}</CapitalizedText>
<Text style={s.cate_detail_price}>{'₹' + data.variants[0].price}</Text>
</View>
<TouchableOpacity activeOpacity={0.7} onPress={this._handle_tag_btn} key={index}>
{
this.state.isTagged ?
<Icon size={icon_size} color="#aaa" name="turned-in-not" />
:
<Icon size={icon_size} color="#aaa" name="turned-in" />
}
</TouchableOpacity>
</View>
</View>
</View>
))
}
</View>
}
</View>
);
}
My output https://i.stack.imgur.com/05uPN.jpg
In this image all bookmarks are selected which is not required.
Any help is appreciated. Thank you.
You can take the bookmark view inside .map and create a new component and then toggle the bookmark status in that component. You pass the data attribute as a prop to this new component -
class Bookmark extends React.Component {
state = { isTagged: false }
_handle_tag_btn() {
if (this.state.isTagged == true) {
this.setState({ isTagged: false })
} else {
this.setState({ isTagged: true })
}
}
render() {
const { data } = this.props
return (
<View style={s.cate_detail_box}>
<TouchableOpacity
activeOpacity={0.9}
style={{ height: 190 }}
onPress={this._goto_individual_detail}
>
<Image source={{ uri: data.images[0].src }} style={s.img} />
</TouchableOpacity>
<View style={{ padding: 5 }}>
<View
activeOpacity={0.9}
style={{ flexDirection: "row", justifyContent: "space-between" }}
>
<View>
<CapitalizedText style={s.cate_detail_title}>
{data.title}
</CapitalizedText>
<Text style={s.cate_detail_price}>
{"₹" + data.variants[0].price}
</Text>
</View>
<TouchableOpacity
activeOpacity={0.7}
onPress={this._handle_tag_btn}
key={index}
>
{this.state.isTagged ? (
<Icon size={icon_size} color="#aaa" name="turned-in-not" />
) : (
<Icon size={icon_size} color="#aaa" name="turned-in" />
)}
</TouchableOpacity>
</View>
</View>
</View>
)
}
}
And then use it inside your .map like this -
this.state.product_detail.map((data, index) => <Bookmark data={data} />)
You could set the tagged object in state, for example:
this.state={ taggedObject: null };
_handle_tag_btn(data) {
if(this.state.taggedObject === data) {
this.setState({taggedObject: null})
}
else {
this.setState({taggedObject: data})
}
}
// ...
<TouchableOpacity activeOpacity={0.7} onPress={() => this._handle_tag_btn(data)} key={index}>
{
this.state.taggedObject === data ?
<Icon size={icon_size} color="#aaa" name="turned-in-not" />:
<Icon size={icon_size} color="#aaa" name="turned-in" />
}
</TouchableOpacity>