Reputation: 117
I'm trying to add style to an element, but the style gets on all elements. How do I get style to just the clicked element and not all of them?
I want the element TouchableOpacity to add the style of listItemsDynmaicOpen when its clicked, witch is does but the problem is that its adding the style to all of my TouchableOpacity elements.
So how do i do to just get style on the pressed TouchableOpacity?
Btw im a total newbie when it comes to React and React-Native
import React, { Component } from 'react';
import { View, StyleSheet, Text, TouchableOpacity } from 'react-native';
import ListItemHeart from './ListItemHeart/ListItemHeart';
class ListItems extends Component {
state = {
ActiveDances: [
{"name":"Agneta & Peter","month":"Jan","day":27,"weekday":"Söndag","place":"Kulturens hus Bollnäs","time":"18.00-21.30","city":"Bollnäs"},
{"name":"Agneta & Peter","month":"Feb","day":23,"weekday":"Fredag","place":"Kulturens hus Bollnäs","time":"18.00-21.30","city":"Bollnäs"},
{"name":"Agneta & Peter","month":"Apr","day":3,"weekday":"Måndag","place":"Kulturens hus Bollnäs","time":"18.00-21.30","city":"Bollnäs"},
{"name":"Agneta & Peter","month":"Aug","day":1,"weekday":"Lördag","place":"Kulturens hus Bollnäs","time":"18.00-21.30","city":"Bollnäs"},
{"name":"Agneta & Peter","month":"Aug","day":1,"weekday":"Lördag","place":"Kulturens hus Bollnäs","time":"18.00-21.30","city":"Bollnäs"},
{"name":"Agneta & Peter","month":"Aug","day":1,"weekday":"Lördag","place":"Kulturens hus Bollnäs","time":"18.00-21.30","city":"Bollnäs"},
{"name":"Agneta & Peter","month":"Aug","day":1,"weekday":"Lördag","place":"Kulturens hus Bollnäs","time":"18.00-21.30","city":"Bollnäs"},
{"name":"Agneta & Peter","month":"Aug","day":1,"weekday":"Lördag","place":"Kulturens hus Bollnäs","time":"18.00-21.30","city":"Bollnäs"},
{"name":"Agneta & Peter","month":"Aug","day":1,"weekday":"Lördag","place":"Kulturens hus Bollnäs","time":"18.00-21.30","city":"Bollnäs"},
],
listClicked: false
};
_showListItem = () => {
if(this.state.listClicked) {
this.setState({
listClicked: false
});
}else{
this.setState({
listClicked: true
});
}
}
render() {
const activedance = this.state.ActiveDances.map((ActiveDance, i) => {
return (
<TouchableOpacity key={i} style={this.state.listClicked ? styles.listItemsDynamicOpen : styles.listItemsDynamicClosed} onPress={this._showListItem}>
<View style={styles.listItemsDate}>
<Text style={styles.listItemsDaytext}>{ActiveDance.day}</Text>
<Text style={styles.listItemsBoldtext}>{ActiveDance.month}</Text>
</View>
<View style={styles.listItemsInfo}>
<Text style={styles.nametext}>{ActiveDance.name}</Text>
<View style={styles.listItemsInfoDayTime}>
<Text style={styles.normaltext}>{ActiveDance.weekday}</Text>
<Text style={styles.normaltext}>{ActiveDance.time}</Text>
</View>
<Text style={styles.normaltext}>{ActiveDance.place}</Text>
<Text style={styles.normaltext}>{ActiveDance.city}</Text>
</View>
<View style={styles.heart}>
<ListItemHeart />
</View>
</TouchableOpacity>
);
});
return (
<View style={styles.listItems}>{activedance}</View>
);
}
}
const styles = StyleSheet.create({
listItems: {
width: "100%",
backgroundColor:"#f2f2f2",
paddingTop:15
},
listItemsDynamicClosed: {
width:"100%",
height:110,
marginBottom: 10,
flexDirection: 'row',
backgroundColor: "white",
},
listItemsDynamicOpen: {
width: "100%",
height: 200,
marginBottom: 10,
flexDirection: "row",
backgroundColor: "white"
},
listItemsDate: {
width:"15%",
height: 50,
alignItems:"center",
marginTop:10
},
heart: {
width:"10%",
alignItems:"center",
justifyContent:"center"
},
listItemsInfo: {
marginLeft:10,
width:"65%"
},
listItemsInfoDayTime: {
width:"60%",
flexDirection:'row',
justifyContent:'space-between'
},
listItemsDaytext:{
fontSize: 20,
color:"#39B54A"
},
listItemsBoldtext: {
fontSize: 19
},
nametext:{
paddingTop:5,
paddingBottom:5,
fontSize:19,
color:"#808080"
},
normaltext: {
fontSize: 16,
paddingTop:1,
paddingBottom:1,
color:"#4d4d4d"
}
});
export default ListItems;
Upvotes: 1
Views: 1698
Reputation: 83
You need to differentiate between different touchables. You should not use array index for this ( as your "key" prop is currently ), it would be great if it was some unique id. But in this case, I can show how to do it with the array index for simplicity.
Your state:
state = { ActiveDances: "your list", selectedDance: null }
On dance select:
_showListItem = (index) => {
if(this.state.selectedDance === index) { // if the dance is selected, unselect it
this.setState({
selectedDance: null
});
} else { // if the dance is not selected, select it
this.setState({
selectedDance: index
});
}
}
Your touchable:
<TouchableOpacity
key={i}
style={this.state.selectedDance === i ? styles.listItemsDynamicOpen :
styles.listItemsDynamicClosed}
onPress={() => this._showListItem(i)}>
Upvotes: 1
Reputation: 1760
Your state for tracking the click listClicked
is getting shared through all the TouchableOpacity
items. If we try to simulate what happens when this.state.ActiveDances.map
executes, it returns all the ActiveDances
items like:
<TouchableOpacity key=0 style={styles.listItemsDynamicClosed> </TouchableOpacity>
<TouchableOpacity key=1 style={styles.listItemsDynamicClosed> </TouchableOpacity>
<TouchableOpacity key=2 style={styles.listItemsDynamicClosed> </TouchableOpacity>
......
Notice here styles.listItemsDynamicClosed
is because of this expression this.state.listClicked ? styles.listItemsDynamicOpen : styles.listItemsDynamicClosed}
since this.state.listClicked
is still false
as you have not clicked yet.
Now when you click and this.state.listClicked
is true
and since all the TouchableOpacity
are sharing it all of them renders as:
<TouchableOpacity key=0 style={styles.listItemsDynamicOpen> </TouchableOpacity>
<TouchableOpacity key=1 style={styles.listItemsDynamicOpen> </TouchableOpacity>
<TouchableOpacity key=2 style={styles.listItemsDynamicOpen> </TouchableOpacity>
......
This is where breaking it into small component comes into play. Imagine if you have one component which is only returning one TouchableOpacity
then you could've listClicked
applied in only one TouchableOpacity
and only the clicked one would update.
//ClickableItem.js
class ClickableItem extends Component {
state = {
listClicked = false,
}
_showListItem = () => {
this.setState({
listClicked: !this.state.listClicked
})
render() {
return(
<TouchableOpacity style={this.state.listClicked ? syles.listItemsDynamicOpen : styles.listItemsDynamicClosed} onPress={this._showListItem}>
...
</TouchableOpacity>
)
}
}
export default ClickableItem
And then in the main/parent component:
//List.js
import ClickableItem from './ClickableItem.js'
class List extends Component {
state = {
ActiveDances: [
{"name":"Agneta & Peter","month":"Jan","day":27,"weekday":"Söndag","place":"Kulturens hus Bollnäs","time":"18.00-21.30","city":"Bollnäs"},
{"name":"Agneta & Peter","month":"Feb","day":23,"weekday":"Fredag","place":"Kulturens hus Bollnäs","time":"18.00-21.30","city":"Bollnäs"},
{"name":"Agneta & Peter","month":"Apr","day":3,"weekday":"Måndag","place":"Kulturens hus Bollnäs","time":"18.00-21.30","city":"Bollnäs"},
{"name":"Agneta & Peter","month":"Aug","day":1,"weekday":"Lördag","place":"Kulturens hus Bollnäs","time":"18.00-21.30","city":"Bollnäs"},
{"name":"Agneta & Peter","month":"Aug","day":1,"weekday":"Lördag","place":"Kulturens hus Bollnäs","time":"18.00-21.30","city":"Bollnäs"},
{"name":"Agneta & Peter","month":"Aug","day":1,"weekday":"Lördag","place":"Kulturens hus Bollnäs","time":"18.00-21.30","city":"Bollnäs"},
{"name":"Agneta & Peter","month":"Aug","day":1,"weekday":"Lördag","place":"Kulturens hus Bollnäs","time":"18.00-21.30","city":"Bollnäs"},
{"name":"Agneta & Peter","month":"Aug","day":1,"weekday":"Lördag","place":"Kulturens hus Bollnäs","time":"18.00-21.30","city":"Bollnäs"},
{"name":"Agneta & Peter","month":"Aug","day":1,"weekday":"Lördag","place":"Kulturens hus Bollnäs","time":"18.00-21.30","city":"Bollnäs"},
]
}
render() {
return(
this.state.ActiveDances.map((ActiveDance, i) => <ClickableItem key={i}>)
)
}
}
Anything data that you need to pass to the children components (ClickableItem
in this case) you can pass it down as props and receive it through this.props
. More info: https://reactjs.org/docs/components-and-props.html
And since you are new take a look on good practices in javascript codes. One thing I'd like to point out: use camelCase when naming variable references. For react capital case on the beginning of a name should be used for tag/component names only.
I hope it helps you. Welcome to React and React Native :)
Upvotes: 1
Reputation: 2036
Well, you can use this trick. You can use TouchableHighlight
:
import React, { Component } from 'react';
import { View, StyleSheet, Text, TouchableOpacity, TouchableHighlight } from 'react-native';
import ListItemHeart from './ListItemHeart/ListItemHeart';
class ListItems extends Component {
state = {
ActiveDances: [
{"name":"Agneta & Peter","month":"Jan","day":27,"weekday":"Söndag","place":"Kulturens hus Bollnäs","time":"18.00-21.30","city":"Bollnäs"},
{"name":"Agneta & Peter","month":"Feb","day":23,"weekday":"Fredag","place":"Kulturens hus Bollnäs","time":"18.00-21.30","city":"Bollnäs"},
{"name":"Agneta & Peter","month":"Apr","day":3,"weekday":"Måndag","place":"Kulturens hus Bollnäs","time":"18.00-21.30","city":"Bollnäs"},
{"name":"Agneta & Peter","month":"Aug","day":1,"weekday":"Lördag","place":"Kulturens hus Bollnäs","time":"18.00-21.30","city":"Bollnäs"},
{"name":"Agneta & Peter","month":"Aug","day":1,"weekday":"Lördag","place":"Kulturens hus Bollnäs","time":"18.00-21.30","city":"Bollnäs"},
{"name":"Agneta & Peter","month":"Aug","day":1,"weekday":"Lördag","place":"Kulturens hus Bollnäs","time":"18.00-21.30","city":"Bollnäs"},
{"name":"Agneta & Peter","month":"Aug","day":1,"weekday":"Lördag","place":"Kulturens hus Bollnäs","time":"18.00-21.30","city":"Bollnäs"},
{"name":"Agneta & Peter","month":"Aug","day":1,"weekday":"Lördag","place":"Kulturens hus Bollnäs","time":"18.00-21.30","city":"Bollnäs"},
{"name":"Agneta & Peter","month":"Aug","day":1,"weekday":"Lördag","place":"Kulturens hus Bollnäs","time":"18.00-21.30","city":"Bollnäs"},
],
pressStatus:false,
};
_onHideUnderlay() {
this.setState({ onPressStatus: false });
}
_onShowUnderlay() {
this.setState({ pressStatus: true });
}
render() {
const activedance = this.state.ActiveDances.map((ActiveDance, i) => {
return (
<TouchableHighlight
activeOpacity={1}
style={
this.state.pressStatus
? styles.listClicked
: styles.listItemsDynamicOpen
}
onHideUnderlay={this._onHideUnderlay.bind(this)}
onShowUnderlay={this._onShowUnderlay.bind(this)}
>
<View style={styles.listItemsDate}>
<Text style={styles.listItemsDaytext}>{ActiveDance.day}</Text>
<Text style={styles.listItemsBoldtext}>{ActiveDance.month}</Text>
</View>
<View style={styles.listItemsInfo}>
<Text style={styles.nametext}>{ActiveDance.name}</Text>
<View style={styles.listItemsInfoDayTime}>
<Text style={styles.normaltext}>{ActiveDance.weekday}</Text>
<Text style={styles.normaltext}>{ActiveDance.time}</Text>
</View>
<Text style={styles.normaltext}>{ActiveDance.place}</Text>
<Text style={styles.normaltext}>{ActiveDance.city}</Text>
</View>
<View style={styles.heart}>
<ListItemHeart />
</View>
</TouchableHighlight >
);
});
return (
<View style={styles.listItems}>{activedance}</View>
);
}
}
Upvotes: 0