React-Native refresh Flatlist not working on Android - react-native

When a user presses a flatlist populated by gpsDataSource
this.state = {
gpsDataSource: [
{ selected: false, title: I18n.t('Settings_precise_11f271'), code: 'precise' },
{ selected: false, title: I18n.t('Settings_approximate_b23bbf'), code: 'approximate' },
{ selected: true, title: I18n.t('Settings_off_810357'), code: 'off' },
],
};
Populated through
<FlatList
data={this.state.gpsDataSource}
extraData={this.state.refresh}
renderItem={({ item, index }) =>
<View>
{(Platform.OS === 'android') ?
<TouchableNativeFeedback onPress={() => this._onGPSPress(item)} background={TouchableNativeFeedback.SelectableBackground()} >
<View>
<MenuItem
item={item}
navigation={this.props.navigation}
/>
</View>
</TouchableNativeFeedback>
:
<TouchableHighlight
onPress={() => this._onGPSPress(item)}
underlayColor='gray'>
<MenuItem
item={item}
onPress={() => this._onGPSPress(item)}
navigation={this.props.navigation}
/>
</TouchableHighlight>
}
</View>
}
keyExtractor={(item, index) => index.toString()}
/>
The user selects an item
_onGPSPress(_click) {
this.state.gpsDataSource.map(element => {
if (element.code == _click.code)
{console.log("match"); element.selected = true; return element }
else { console.log("no match");element.selected = false ; return element }
});
this.setState({
refresh: !this.state.refresh
})
//Todo: appropriate server calls
}
The flatlist refreshed on iOS but not Android (incidentally, Menuitem is identical for both platforms.
How can I get the flatlist (a selected blue point is in menu item) to refresh for Android?

Related

Expo : Select Multiple item of flatlist ( change style)

I'm trying to add a badge on a View ,by a TouchableOpacity on press.
The trouble is the animation work appears only on one element at a time and not on two or more simultaneously
Here the code :
Flatlist :
<FlatList
data={this.state.ReturnedArray}
width='100%'
ItemSeparatorComponent={this.FlatListItemSeparator}
keyExtractor={(item, index) => 'key' + index}
renderItem={this.renderizza}
extraData={this.state.activeItem}
/>
Render funtion :
<View style={style.containerFlat}>
<View style={style.containerFlat1}>
<Text style={style.txt}>{item.name} {item.cognome}</Text>
</View>
<TouchableOpacity style={style.containerFlat2} onPress={() => this.badge(item.expoToken,index)}>
{(this.state.activeItem === index) ? <Animated.View style={[style.animatedView, { opacity: this.state.fadeValue }]}><Text>ADDED</Text></Animated.View> : null}
<Text style={style.AvatarTxt} >{acronym}</Text>
</TouchableOpacity>
</View>
Badge function add Token into an array and lunch animation :
badge(chiavi, index) {
if ((this.state.SelectedUser).includes(chiavi)) {
this.Nonanimate(index)
this.state.SelectedUser.splice(this.state.SelectedUser.indexOf(chiavi), 1)
} else {
this.state.SelectedUser.push(chiavi)
this.animate(index)
}
}
and the animation / NotAnimation :
animate = (index) => {
this.setState({
activeItem: index,
});
Animated.timing(this.state.fadeValue, {
toValue: 1,
duration: 0
}).start()
};
Nonanimate = index => {
this.setState({
activeItem: index,
});
Animated.timing(this.state.fadeValue, {
toValue: 0,
duration: 0
}).start()
};
i'm wasting days on this trouble. Suggest ?
Here the function to solve this :
badge = chiavi => {
//console.log(chiavi.item.expoToken)
if ((this.state.SelectedUser).includes(chiavi.item.expoToken)) {
// this.Nonanimate(index)
this.state.SelectedUser.splice(this.state.SelectedUser.indexOf(chiavi.item.expoToken), 1)
} else {
this.state.SelectedUser.push(chiavi.item.expoToken)
// this.animate(index)
}
chiavi.item.isSelect = !chiavi.item.isSelect;
chiavi.item.selectedClass = chiavi.item.isSelect ?
style.selected : style.containerFlat1;
const index = this.state.ReturnedArray.findIndex(
item => chiavi.item.user_id === item.user_id
);
this.state.ReturnedArray[index] = chiavi.item;
this.setState({
ReturnedArray: this.state.ReturnedArray,
});
and Flatlist :
<FlatList
data={this.state.ReturnedArray}
width='100%'
ItemSeparatorComponent={this.FlatListItemSeparator}
keyExtractor={item => item.user_id.toString()}
renderItem={item => this.renderizza(item)}
extraData={this.state}
/>
Source : Link here

How to get the index value of FlatList in the header using React-native

I need to get the index value of the FlatList used in header of a React native component.
Below is the code I used.I need the parameter rowItem in onPressAction function which is returned as undefined
constructor(props) {
super(props);
this.state = {
selectedItem: '',
headerData: [
{ image: require('common/assets/images/headers/homeicon.png') },
{ image: require('common/assets/images/headers/CustomerDetails2.png') }
]
}
}
componentDidMount() {
// Event Listener for orientation changes
Dimensions.addEventListener('change', () => {
this.setState({
orientation: isPortrait() ? 'portrait' : 'landscape'
});
});
this.props.navigation.setParams({
headerData: this.state.headerData,
selectedItem: this.state.selectedItem,
onPressAction: (item) => this.onPressAction()
});
}
onPressAction = (rowItem) => {
alert(rowItem);
}
static navigationOptions = ({ navigation }) => {
return {
headerTransparent: true,
headerLeft: (
<View style={{ flex: 1, flexDirection: 'row' }} >
<FlatList
horizontal={true}
extraData={navigation.getParam('selectedItem')}
data={navigation.getParam('headerData')}
renderItem={({ item, index }) => (
<TouchableOpacity onPress={navigation.getParam('onPressAction')} >
<Image style={styles.centerIcon} resizeMode='contain' source={item.image}></Image>
</TouchableOpacity>
)}
keyExtractor={(item, index) => index.toString()}
/>
</View >
),
headerTintColor: 'transparent',
};
};
Could anyone please help me
Insert ID into headerData and use it as index value.
headerData: [
{ id: 0 , image: require('common/assets/images/headers/homeicon.png') },
{ id: 1 , image: require('common/assets/images/headers/CustomerDetails2.png') }
]
...
}
renderItem={({ item, index }) => (
<TouchableOpacity onPress={() => alert(navigation.getParam('onPressAction'))} >
<Image style={styles.centerIcon} resizeMode='contain' source={item.image}></Image>
</TouchableOpacity>
)}

react-native changes the properties of the elements in the array?

I have a FlatList and I want to implement a radio button.My idea is to change the selected property of an element in this.state.data to control it,but I am a newbie, I don't know how to change the property of an element in this.state.data.
Here is my code:
this.state = {
data: [
{
month:1,
price:18,
selected:true
},
{
month:3,
price:48,
selected:false
},
{
month:12,
price:128,
selected:false
},
],
};
<FlatList
data={this.state.data}
renderItem={({item, index, separators}) => (
<TouchableOpacity onPress={() => this.radio(index,item)}>
<View style={item.selected ? {borderWidth:3,borderColor:'#FFA371',borderRadius:15}:{}}>
<View style={styles.itemDefalut}>
<View style={{ flexDirection: "column", flex: 1 }}>
<Text>
Months
</Text>
<Text>{item.month} Months</Text>
</View>
<View>
<Text>${item.price}</Text>
</View>
</View>
</View>
</TouchableOpacity>
)}
/>
radio(index,item) {
for (var variable in this.state.data) {
variable.selected = false;
}
item.selected = true;
}
first pass only index from onpress
onPress={() => this.radio(index)
then in radio function do something like this
radio = index => {
let data = [ ...this.state.data ];
this.state.data.map((elem,key)=>{
if(elem.month==data[index].month){
data[key]={...data[key], selected: true};
}else{
data[key]={...data[key], selected: false};
}
})
this.setState({ data:data});
}
radio(item) {
let data = [...this.state.data];
let index = data.findIndex(el => el.month === item.month);
data[index] = {...data[index], selected: !item.selected};
this.setState({ data });
}
In TouchableOpacity on press it should be
<TouchableOpacity onPress = {this.radio.bind(this,item)}>

react-native flatlist not rerendering

Funny one this.
My flatlist rerenders on iOS but not android. That is - the flatlist renders and changes when I click on an item as I would expect from my code.
Flatlist code:
<FlatList
data={this.state.languageDataSource}
extraData={this.state.refresh}
renderItem={({ item, index }) =>
<View>
{(Platform.OS === 'android') ?
<TouchableNativeFeedback onPress={() => this._onPress(item)} background={TouchableNativeFeedback.SelectableBackground()} >
<View>
<MenuItem
item={item}
english={this.state.english}
navigation={this.props.navigation}
generateTestHook={this.props.generateTestHook.bind(this)}
/>
</View>
</TouchableNativeFeedback>
:
<TouchableHighlight
onPress={() => this._onPress(item)}
underlayColor='gray'>
<MenuItem
item={item}
english={this.state.english}
navigation={this.props.navigation}
generateTestHook={this.props.generateTestHook.bind(this)}
/>
</TouchableHighlight>
}
</View>
}
keyExtractor={(item, index) => index.toString()}
/>
When we click we get
_onGPSPress = (_click) => {
this.state.gpsDataSource.forEach(element => {
if (element.code == _click.code) { element.selected = true } else { element.selected = false; this.setState({
refresh: !this.state.refresh
}) }
});
this.setState({
refresh: !this.state.refresh
})
//Todo: appropriate server calls
}
and it seems on logging that setstate does not work. Any ideas?
UPDATE:
This is to do with the way I am setting the state for the datasource which is:
gpsDataSource: [
{ selected: false, title: I18n.t('Settings_precise_11f271'), code: 'precise' },
{ selected: true, title: I18n.t('Settings_approximate_b23bbf'), code: 'approximate' },
{ selected: false, title: I18n.t('Settings_off_810357'), code: 'off' },
]
So how can I set the individual "selected" bools?
If you feel there is an issue with setState then please try below code:
this.setState(prevState => ({
refresh: !prevState.refresh
}));

Handle Multiselect in a GridView

I'm trying to handle the multi-select with react-native-super-grid , here is my code :
<GridView
itemDimension={80}
items={items}
style={styles.gridView}
renderItem={item => (
<View style={[styles.itemContainer , { backgroundColor:' transparent '}]}>
<TouchableHighlight style={styles.buttonStyle} onPress={() => this.pressEvent() }>
<Text> {item.image}</Text>
</TouchableHighlight>
<Text style={styles.buttonText}> {item.name}</Text>
</View>)}
/>
I tried using this function :
pressEvent(arr){
if(this.state.pressStatus == false){
this.setState({ pressStatus: true})
this.state.arr.push(arr)
this.setState({ color : 'white'})
} else {
this.setState({ pressStatus: false})
this.setState({ color: 'red'})
}
}
but it somehow doesn't work , can someone help me ?
Thank you .
This short example should give you an idea what are you doing wrong. The items itself are not aware of the state. So what I would do, I would create a separate child component for grid item and handle press state locally. Then handle parent, which is holding all the item trough callback about the pressed item.
class MyGridView extends Component {
render() {
return (
<GridView
itemDimension={80}
items={items}
style={styles.gridView}
renderItem={item => (
<GridItem
item={item}
onItemPress={selected => {
// set grid view callback
if (selected) {
//if true add to array
this.addToPressedArray(item);
} else {
//false remove from array
this.removeFromPressedArray(item);
}
}}
/>
)}
/>
);
}
// You don't change the state directly, you mutate it trough set state
addToPressedArray = item => this.setState(prevState => ({ arr: [...prevState.arr, item] }));
removeFromPressedArray = item => {
const arr = this.state.arr.remove(item);
this.setState({ arr });
};
}
And the GridItem
class GridItem extends Component {
// starting local state
state = {
pressStatus: false,
color: 'red'
};
// handle on item press
pressEvent = () => {
this.setState(prevState => ({
pressStatus: !prevState.pressStatus, //negate previous on state value
color: !prevState.pressStatus ? 'white' : 'red' //choose corect collor based on pressedStatus
}));
// call parent callback to notify grid view of item select/deselect
this.props.onItemPress(this.state.pressStatus);
};
render() {
return (
<View style={[styles.itemContainer, { backgroundColor: ' transparent ' }]}>
<TouchableHighlight style={styles.buttonStyle} onPress={() => this.pressEvent()}>
<Text> {item.image}</Text>
</TouchableHighlight>
<Text style={styles.buttonText}> {item.name}</Text>
</View>
);
}
}
I also recommend to read about React.Component lifecycle. Its a good reading and gives you a better understanding how to achieve updates.
Since GridView has been merged into FlatGrid. Therefore, I've implemented the multi-select option in a pretty easy way. First of all I applied TouchableOpacity on top of the view in the renderItems prop of FlatGrid like this.
<TouchableOpacity
onPress={() => this.selectedServices(item.name)}>
...props
</TouchableOpacity>
SelectedServices:
selectedServices = item => {
let services = this.state.selectedServices;
if (services.includes(item) == false) {
services.push(item);
this.setState({ selectedServices: services });
} else {
let itemIndex = services.indexOf(item);
services.splice(itemIndex, 1);
this.setState({ selectedServices: services });
}
};
Using splice, indexOf, and push, you can easily implement multi-selection.
To change the backgroundColor of the currently selected item, you can apply a check on the backgroundColor prop of the view.
renderItem={({ item, index }) => (
<TouchableOpacity
onPress={() => this.selectedServices(item.name)}
>
<View
style={[
styles.itemContainer,
{
backgroundColor: this.state.selectedServices.includes(
item.name
)
? '#0052cc'
: item.code
}
]}
>
<Text style={styles.itemName}>{item.name}</Text>
</View>
</TouchableOpacity>
)}