How to fix JSX expression must have one parent element? - reactjs

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,

Related

How to view a component in onPress of React-Native-Paper Chip component

I want to show a Add button when I click Chip's onPress. The component I want to display is onPressChip() function. This is my code.
const Item = ({title}) => (
<View>
<Chip onPress={() => onPressChip()} style={{margin: 'auto'}}>
{title}
</Chip>
</View>
);
const onPressChip = () => {
<View style={{flexDirection: 'row-reverse', marginTop: 10}}>
<Button
disabled={false}
icon={'plus'}
mode="contained"
onPress={() => onClickAddButton()}
color={'#0AB155'}
style={{left: 0, marginTop: 5}}>
{'Add'}
</Button>
</View>;
};
const GradingList = ({DATA}) => {
return (
<SafeAreaView style={styles.container}>
<FlatList
data={DATA}
horizontal={true}
renderItem={({item}) => <Item title={item.name} />}
keyExtractor={item => item.id}
/>
</SafeAreaView>
);
};
export default GradingList;
But it does not work. Please help.
Take one boolean state variable based on that you can manage the view or hide button:
const[isButtonVisible,setIsButtonVisible]=useState(false)
const Item = ({title}) => (
<View>
<Chip onPress={() => setIsButtonVisible(!isButtonVisible)} style={{margin: 'auto'}}>
{title}
</Chip>
</View>
);
const onPressChip = () => {
return( <View style={{flexDirection: 'row-reverse', marginTop: 10}}>
<Button
disabled={false}
icon={'plus'}
mode="contained"
onPress={() => onClickAddButton()}
color={'#0AB155'}
style={{left: 0, marginTop: 5}}>
{'Add'}
</Button>
</View>)
};
const GradingList = ({DATA}) => {
return (
<SafeAreaView style={styles.container}>
<FlatList
data={DATA}
horizontal={true}
renderItem={({item}) => <Item title={item.name} />}
keyExtractor={item => item.id}
/>
{isButtonVisible&&onPressChip()}
</SafeAreaView>
);
};
export default GradingList;
This will add a button after all flatlist data is shown.

React Native - ScrollView not scrolling

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}}>

How to make Detail Screen from flat list React Native Expo

I am trying to open new screen with flat list from Notification. Output like this from Pages Notification (when click the blue, move to another pages).
Here is my notification screen
and this is my detail screen
and this is my Notification View
_renderItem = ({item}) => (
<TouchableOpacity onPress={() => this.props.navigation.navigate('LogHistoryDetail', {UserEmail: this.props.navigation.state.params.UserEmail})}>
<Text style = {styles.item}> {item.history_content}</Text>
</TouchableOpacity>
);
render() {
return (
<View style={styles.container}>
<TouchableOpacity style={styles.btn} onPress={() => this.props.navigation.navigate('HomeScreen')}>
<Ionicons name="arrow-back-circle" size={30} color="black" />
</TouchableOpacity>
<Text style = {{fontSize:30, alignContent:"flex-start", color:'black'}}>Notification</Text>
<FlatList
data={this.state.data}
renderItem = {this._renderItem}
keyExtractor = { (item, index) => index.toString() }
/>
</View>
);
}
}
and this is my Detail Screen View
_renderItem = ({item}) => (
<View style = {{backgroundColor:'#1E90FF',margin:15, justifyContent: 'center', borderTopRightRadius: 15,
borderTopLeftRadius: 15, borderBottomEndRadius: 15, borderBottomLeftRadius: 15 }}>
<Text style = {{fontSize:15,margin:15, justifyContent: 'center' ,color:'white'}}> ID Log: {item.id_log}</Text>
<Text style = {{fontSize:15,margin:15, justifyContent: 'center' ,color:'white'}}> Email: {this.props.navigation.state.params.UserEmail}</Text>
<Text style = {{fontSize:15,margin:15, justifyContent: 'center' ,color:'white'}}> History Title: {item.history_title}</Text>
</View>
);
render() {
return (
<View style={styles.container}>
<TouchableOpacity style={styles.btn2} onPress={() => this.props.navigation.navigate('LogNotification')}>
<Ionicons name="arrow-back-circle" size={30} color="black" />
</TouchableOpacity>
<Text style={styles.headerTxt}>History Detail</Text>
<View style={styles.subView}>
<FlatList
data={this.state.data}
renderItem = {this._renderItem}
keyExtractor = { (item, index) => index.toString() }
/>
</View>
</View>
);
}
}
It seems like i got the wrong output on Detail Screen. I want to get output like this without picture.
Is it possible to make Detail Screen like that? Any suggestion that i need to change my View code or wrong render?
Thank you

How to use props and navigation route in same const function (react native)?

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

change state individually in react-native

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>

Resources