React-Native How to change state value for each item? - javascript

I have a 'touchableOpacity' where each time its pressed it shows the selected value, but when a value is selected every item gets that value.
I need to do it this way:
item 1 -> selectedValue3
item 2 -> selectedValue1...
{ this.state.proyectosConTodo.map((item,index)=>{ return (
<View style={{paddingBottom:12}}>
<Grid>
<Col>
<View style={{height:40,justifyContent: 'center'}}>
<Text numberOfLines={1} allowFontScaling={false} style={{color: '#45526e',fontFamily: 'Roboto-Regular',fontSize:15, alignSelf: 'flex-start'}}>{item.proyecto.titulo}</Text>
</View>
</Col>
<Col>
<TouchableOpacity style={{ height:40,borderWidth:1, borderRadius:4, borderColor: '#e0e4eb', justifyContent: 'center',backgroundColor: '#f3f4f6'}} onPress={()=>{ this.setAgentesReasignarEnviar(item,index) }}>
<Text allowFontScaling={false} style={{color: '#45526e',fontFamily: 'Roboto-Medium',fontSize:15, marginLeft:10,marginRight:10}}>{this.state.txt_agenteProyecto}</Text>
<Icon style={{position: 'absolute',top:13,right:10}} name={ 'chevron-down'} size={10} color={ '#45526e'}/>
</TouchableOpacity>
</Col>
</Grid>
</View>
) }) }

From your snippet it seems that your structure is that one screen with a FlatList or something similar that renders multiples of your TouchableOpacity components. The problem is that every time a single TouchableOpacity is clicked it changes the state of the screen(not just itself) causing all touchable opacities to have that value.
One possible solution is the create another component which renders your list item and has its own state. The item used to render it can be passed as a prop and then calling setState inside that component will not affect the other list items.

I think this is what you need:
setAgentesReasignarEnviar(item, index) {
const result = this.state.proyectosConTodo.map(() => return item);
this.setState({
proyectosConTodo: result
});
}
For more detail, check this out: How to replace all undefined values in an array with "-" ?

Related

How to make a dropdown for every FlatList item?

Kind of surprised at the lack of information I can find about this question, feel like its something that you be done pretty often? I know with a standard dropdown it's pretty easy, you set up a hook that controls state with a boolean, when that boolean is true, you show the dropdown, when it's false, you show the closed version.
The Issue that I discovered when trying to do this with each render item is that the hook state control needs to be in the global context, because of this whenever you click on Flatlist item, all of the items open because they are all using the same state control. How would you make it so that each rendered item has its own dropdown state when you can't set a state hook inside each render item?
Here's my code to give you a better idea of what I'm talking about, be sure to read the comments:
<FlatList
contentContainerStyle={{ alignItems: 'center', marginVertical: 10, minHeight: 200 }}
data={notes}
keyExtractor={(item, index) => item.key}
ListFooterComponent={() => <AddNoteFooter onPress={addSpecificNote} />}
renderItem={({ item }) => {
//would need something similar to a hook right here,
// to manage the state of each item individually
//change "isOpen" state when button is pressed
return (
<View>
{!isOpen &&
<TouchableOpacity onPress={null} style={styles.flastliststyle}>
<Text style={styles.flastlistItemText}>{item.note}</Text>
</TouchableOpacity>
}
{isOpen &&
<TouchableOpacity>
/* extended dropdown code */
</TouchableOpacity>
}
</View>)
}
Looking to do something similar to this video but where each item is a flatlist item (also using hooks):
https://www.youtube.com/watch?v=awEP-pM0nYw&t=134s
Thank you!
SOLUTION:
flatlist:
<FlatList
contentContainerStyle={{ alignItems: 'center', marginVertical: 10, minHeight: 200 }}
data={notes}
keyExtractor={(item, index) => item.key}
ListFooterComponent={() => <AddNoteFooter onPress={addSpecificNote} />}
renderItem={({ item }) => {
return (
<NoteItem noteitem={item} />
)
}}
/>
then the component rendered for each item:
const NoteItem = (props) => {
const [isOpen, updateDrop] = useState(false)
return (
<View>
{!isOpen &&
<TouchableOpacity onPress={() => updateDrop(prev => !prev)} style={styles.flastliststyle}>
<Text style={styles.flastlistItemText}>{props.noteitem.note}</Text>
</TouchableOpacity>
}
{isOpen &&
<TouchableOpacity onPress={() => updateDrop(prev => !prev)} style={styles.flastliststyle}>
<Text style={styles.flastlistItemText}>pressed</Text>
</TouchableOpacity>
}
</View>
)
}

React Native FlatList keyboardShouldPersistTaps not persisting

I have a very frustrating situation. Trying to get keyboard to disappear and detect onPress event handler in child row.
Here is what my code looks like:
_renderRow = (prediction) => {
return (
<TouchableOpacity onPress={() => {
Keyboard.dismiss();
this.setState({ location: prediction.description });
}}>
<View style={styles.listItemContainer}>
<Text>{prediction.description}</Text>
</View>
</TouchableOpacity>
)
}
render() {
return (
<View style={styles.wrapper}>
{/* style={[this.state.predictions.length > 0 ? styles.searchContainerSuggest : styles.searchContainer]} */}
<View style={styles.searchContainerSuggest}>
<View style={{paddingLeft: 10, height: 45, display: 'flex', justifyContent: 'center'}}>
<TextInput
placeholder="Enter location"
value={this.state.location}
onChangeText={location => this.onChangeLocation(location)}
style={styles.textInput}
/>
</View>
{this.state.predictions.length && this.state.location !== '' ?
<FlatList
keyboardShouldPersistTaps={'handled'}
refreshing={!this.state.loaded}
initialNumToRender={10}
enableEmptySections={true}
data={this.state.predictions}
keyExtractor={(_, index) => index.toString()}
renderItem={ ({item: prediction}) => this._renderRow(prediction) } />
: null}
</View>
</View>
);
}
I probably need a helping hand or two with regards to how to debug this issue.
Looked up several examples on how to deal with hiding the keyboard and allowing a particular selection to be pressed at the same time.
I thought that keyboardShouldPersistTaps would allow for the child selection to be selected. Upon selection, the onPress event handler will trigger and that will be where I call Keyboard.dismiss() to hide the keyboard. Does not seem to work.
In my case, besides adding keyboardShouldPersistTabs='handled' to the FlatList in question, it was also needed to add keyboardShouldPersistTabs='handled' and nestedScrollEnabled={true} to a parent ScrollView like 2 levels above, wrapping the FlatList I intended to get this behavior with. Check out this issue in react-native repo for more info.
For anyone who is running into the same problem as me. Check whether your FlatList or ScrollView is nested in another FlatList or ScrollView.
If yes, then add
keyboardShouldPersistTaps='handled'
to the element as a props as well.
add keyboardDismissMode="none" to FlatList

How to toggle a single element coming from a map iteration in react native?

I have a toggle function to change a property in the state:
toggleSelected = () => {
this.setState({selected:!this.state.selected})
}
I also have a map function to iterate some data:
data.allRoomTypes.edges.map( c =>
<TouchableOpacity key={c.node.roomTypeId} onPress={this.toggleSelected}>
<Row style={styles.boxWithShadow}>
<Col style={{marginLeft:160}}>
<View style={{flex:1, flexDirection:"row"}}>
{this.state.selected === false ? <Image style={styles.center} source={require("../../images/roomtypes/radio_btn_unselected.png")}/> : <Image style={styles.center} source={require("../../images/roomtypes/radio_btn_selected.png")}/>}
</View>
</Col>
</Row>
</TouchableOpacity>
)
I wanna that when I click on any row, the toggle will be only worked on that row, other rows will not be changed. But the thing is that when I click on any row, all rows are changed. What are the solutions for this problem?
Thanks!
Your issue is you are using the same state variable selected to track the state of all components in the map.
I would try something like this (I cant test at the moment but i think you will get the idea):
toggleSelected = (index) => {
var selected = this.state.selected
selected[index] = !selected[index]
this.setState({selected:selected})
}
data.allRoomTypes.edges.map( (c, index) =>
<TouchableOpacity key={c.node.roomTypeId} onPress={(index) => this.toggleSelected(index)}>
<Row style={styles.boxWithShadow}>
<Col style={{marginLeft:160}}>
<View style={{flex:1, flexDirection:"row"}}>
{this.state.selected[index] === false ? <Image style={styles.center} source={require("../../images/roomtypes/radio_btn_unselected.png")}/> : <Image style={styles.center} source={require("../../images/roomtypes/radio_btn_selected.png")}/>}
</View>
</Col>
</Row>
</TouchableOpacity>
)
The idea being your selected state is an object {} itself with a key for every index representing the TouchableOpacity elements.
Note: The above code assumes you are initializing the selected object somewhere in your code. Like selected = {1:False, 2:True...}

Reactjs assigning key prop to array rendered components

I am rendering some components using array map function, and I'm getting "Each child in an array or iterator should have a unique "key" prop." warning. I know that I do have to assign key props to the array rendered components.
My question is, do I have to just assign key to the most outer component (this case View) that is inside the map function, or do I have to assign key to every element inside the outer most component view?
If latter is the case, then assigning key to every component is a little inefficient I think? Is there any way to solve this problem? Thank you
this.state.Store.City.map((item) => {
return <View>
<TouchableOpacity onPress={() => this.onQueryInputChange(item)}>
<Text style={{ fontSize: 20, paddingVertical: 10 }}>
{item.fullName}
</Text>
</TouchableOpacity>
</View>
})
If you don't have an id in item, you can use the item array index if the list will not be reordered or reorganized :
this.state.Store.City.map((item, index) => {
return (
<View key={index}>
<TouchableOpacity onPress={() => this.onQueryInputChange(item)}>
<Text style={{ fontSize: 20, paddingVertical: 10 }}>
{item.fullName}
</Text>
</TouchableOpacity>
</View>
);
})
Only the outermost component needs a key to keep track of each item.
You should assign a key to the most outter component (here it would be View component)
here is the documentation
if item has an ìd property you could write
this.state.Store.City.map((item) => {
return (
<View key={item.id}>
<TouchableOpacity onPress={() => this.onQueryInputChange(item)}>
<Text style={{ fontSize: 20, paddingVertical: 10 }}>
{item.fullName}
</Text>
</TouchableOpacity>
</View>
);
})

React-Native how to update Flat List updating item dynamically?

I wanted to update the List based on the 'address' and attach more
codes to it.
I wanted to update the existing Flistlist that is already populated with new incoming data
ANSWER: I got it now. I need to update my list using state change and FlatList Renders my list as new list everytime I update it, therefore data will remain updated everytime.
like:
if(address=='xyz')
{ code= code+newCode; }
<FlatList
extraData={this.state}
data={this.state.TESTDATA}
keyExtractor={(item, index) => item.Code.toString()}
renderItem={({ item}) => (
<TouchableOpacity
onPress={() => console.log('pressed TouchableOpacity')}
style={{
height: 75,
}}
>
<View style={styles.listItem}>
<Text style={styles.baseText}>
Stop Address: {item.Address}{'\n'}
codes: {item.Code}
</Text>
</View>
</TouchableOpacity>
)}
/>

Categories

Resources