Flatlist Multiple item Selection not working on React Native - react-native

I am creating a multi-select grid Flatlist and it seems to work fine in IOS phone but it doesn't work at all on Android phone. On IOS it can select an item when clicked, but on Android it just flickers when you select/click an item.
I am really, really can't figure it out. Please help.
Thank you,
[Flatlist-Grid as per code][1]
import {
View, TouchableOpacity, StyleSheet, Text, ScrollView,
Image,
} from 'react-native'
import { MaterialIcons } from '#expo/vector-icons';
export default class StoreSelector extends Component {
constructor() {
super()
this.state = {
dataList: [
{ name: 'exp: date', key: '#ffsdsf', image: <Image style={{ height: 110, width: 110, backgroundColor: 'red' }} /> },
{ name: 'exp: date', key: '#01713f', image: <Image style={{ height: 110, width: 110, backgroundColor: 'red' }} /> },
{ name: 'exp: date', key: '#fsdaff', image: <Image style={{ height: 110, width: 110, backgroundColor: 'red' }} /> },
{ name: 'exp: date', key: '#00b0a6', image: <Image style={{ height: 110, width: 110, backgroundColor: 'red' }} /> },
{ name: 'exp: date', key: '#ffgadsf', image: <Image style={{ height: 110, width: 110, backgroundColor: 'red' }} /> },
{ name: 'exp: date', key: '#fdfdf', image: <Image style={{ height: 110, width: 110, backgroundColor: 'red' }} /> },
{ name: 'exp: date', key: '#fsdff', image: <Image style={{ height: 110, width: 110, backgroundColor: 'red' }} /> },
{ name: 'exp: date', key: '#ec008c', image: <Image style={{ height: 110, width: 110, backgroundColor: 'red' }} /> },
{ name: 'exp: date', key: '#005baa', image: <Image style={{ height: 110, width: 110, backgroundColor: 'red' }} /> },
{ name: 'exp: date', key: '#fceff', image: <Image style={{ height: 110, width: 110, backgroundColor: 'red' }} /> },
{ name: 'exp: date', key: '#ffwf', image: <Image style={{ height: 110, width: 110, backgroundColor: 'red' }} /> },
{ name: 'exp: date', key: '#000', image: <Image style={{ height: 110, width: 110, backgroundColor: 'red' }} /> },
{ name: 'exp: date', key: '#ea3440', image: <Image style={{ height: 110, width: 110, backgroundColor: 'red' }} /> },
]
}
}
componentDidMount() {
let arr = this.state.dataList.map((item, index) => {
this.isSelected = false
return { ...item }
})
this.setState({ dataList: arr })
}
selectionHandler = (ind) => {
const { dataList } = this.state
let arr = dataList.map((item, index) => {
if (ind == index) {
item.isSelected = !item.isSelected
}
return { ...item }
})
this.setState({ dataList: arr })
}
render() {
const { dataList } = this.state
return (
<View style={styles.scrollContainer}>
<ScrollView >
<View style={styles.container}>
{
dataList.map((item, index) => {
return (
<TouchableOpacity
key={item.key}
onPress={() => this.selectionHandler(index)}
style={styles.boxContainer}>
<View style={styles.img}>{item.image}</View>
<View>{item.isSelected ? <MaterialIcons name="check-box" size={24} color="#fbbe2f" /> : <MaterialIcons name="check-box-outline-blank" size={24} color="grey" />}</View>
</TouchableOpacity>
)
})
}
</View>
</ScrollView>
</View>
)
}
}
const styles = StyleSheet.create({
scrollContainer: {
flex: 1,
},
container: {
flex: 1,
flexDirection: 'row',
flexWrap: 'wrap',
alignItems: 'center',
},
boxContainer: {
height: 110,
width: 110,
margin: 7,
},
img: {
elevation: 5,
alignItems: 'center',
justifyContent: 'center',
position: 'absolute',
shadowColor: '#000',
shadowOffset: { width: 1, height: 2 },
shadowOpacity: .3,
shadowRadius: 3,
borderWidth: 0.5,
borderColor: '#eee'
}
})
[1]: https://i.stack.imgur.com/hrRVS.png

You have given elevation to image element which is appearing above your checkbox so on select action it gets selected but not visible as it is under the image.
Now question is how will you see the checkbox?
Option 1: Remove the elevation
img: {
alignItems: 'center',
justifyContent: 'center',
position: 'absolute',
shadowColor: '#000',
shadowOffset: { width: 1, height: 2 },
shadowOpacity: .3,
shadowRadius: 3,
borderWidth: 0.5,
borderColor: '#eee'
}
Option 2: Make the elevation of the icons higher then the image elevation
<View>
{item.isSelected ?
<MaterialIcons name="check-box" size={24} color="#fbbe2f" style={{elevation:10}}/>
:
<MaterialIcons name="check-box-outline-blank" size={24} color="grey" style={{elevation:10}}/>}
</View>

Related

Style "currentLocationLabel" from react-native-google-places-autocomplete

I'm using react-native-google-places-autocomplete, and i would like to style currentlocation label to make it a marker icon + text,and i also want to make it visible once in the screen not till clicking on the textinput.
my code looks like this:
export default class VilleC extends React.Component {
render() {
loc = () => {
return(
<View style={{flexDirection:'row',marginLeft:10}}>
<EntypoI color={'grey'} size={20} name={'direction'} />
<Text style={{color:'black',marginLeft:10}}>Autour de moi</Text>
</View>);
}
return (
<View style={{flex:1}}>
<GooglePlacesAutocomplete
placeholder='Où ? (adresse,ville...)'
query={{
key: GOOGLE_PLACES_API_KEY,
language: 'fr', // language of the results
components: 'country:ma',
}}
fetchDetails = {true}
currentLocation={true}
>>>>>>>>>>< currentLocationLabel={// what's in function loc i would like to make it here }
GooglePlacesDetailsQuery = {{
fields: ['geometry']
}}
onPress={(data, details = null) => {console.log(details.geometry.location.lat);
console.log(data.description);
NavigationService.navigate('Résultat',{screen:'Résultats',params:{lien: this.props.route.params.lien, choice: this.props.route.params.choix,lat:details.geometry.location.lat,lng:details.geometry.location.lng,loc:data.description}})
}}
onFail={(error) => console.error(error)}
requestUrl={{
url:
'https://cors-anywhere.herokuapp.com/https://maps.googleapis.com/maps/api',
useOnPlatform: 'web',
}} // this in only required for use on the web. See https://git.io/JflFv more for details. // variable styles can t find error
enablePoweredByContainer={false}
styles={{
textInputContainer: {
backgroundColor: 'rgba(0,0,0,0)',
borderTopWidth: 0,
borderBottomWidth: 0,
},
textInput: {
borderRadius:0,
marginLeft: 3,
marginRight: 3,
height: 38,
color: '#5d5d5d',
fontSize: 16,
paddingLeft:20,
shadowColor: "grey",
shadowOpacity: 0.8,
shadowRadius: 2,
shadowOffset: {
height: 1,
width: 0,
},
elevation: 3,
},
predefinedPlacesDescription: {
color: '#1faadb',
},
}}
/>
</View>
);
}
}
i would really appreciate your help!
You can use the renderRow prop to add an icon to the current location, and you can use the autFocus prop to open the input automatically.
Something like this:
export default class App extends React.Component {
render() {
return (
<View style={{ flex: 1 }}>
<GooglePlacesAutocomplete
placeholder="Où ? (adresse,ville...)"
query={{
key: 'GOOGLE_PLACES_API_KEY',
language: 'fr', // language of the results
components: 'country:ma',
}}
autoFocus={true}
fetchDetails={true}
currentLocation={true}
currentLocationLabel="Autour de moi"
renderRow={(row) =>
row.isCurrentLocation ? (
<View style={{ flexDirection: 'row', marginLeft: 10 }}>
<Text>icon</Text>
<Text style={{ color: 'black', marginLeft: 10 }}>
{row.description}
</Text>
</View>
) : (
<Text>{row.description}</Text>
)
}
GooglePlacesDetailsQuery={{
fields: ['geometry'],
}}
onPress={(data, details = null) => {
console.log(details.geometry.location.lat);
console.log(data.description);
}}
onFail={(error) => console.error(error)}
requestUrl={{
url:
'https://cors-anywhere.herokuapp.com/https://maps.googleapis.com/maps/api',
useOnPlatform: 'web',
}} // this in only required for use on the web. See https://git.io/JflFv more for details. // variable styles can t find error
enablePoweredByContainer={false}
styles={{
textInputContainer: {
backgroundColor: 'rgba(0,0,0,0)',
borderTopWidth: 0,
borderBottomWidth: 0,
},
textInput: {
borderRadius: 0,
marginLeft: 3,
marginRight: 3,
height: 38,
color: '#5d5d5d',
fontSize: 16,
paddingLeft: 20,
shadowColor: 'grey',
shadowOpacity: 0.8,
shadowRadius: 2,
shadowOffset: {
height: 1,
width: 0,
},
elevation: 3,
},
predefinedPlacesDescription: {
color: '#1faadb',
},
}}
/>
</View>
);
}
}

My row item updates itself automatically into the deleted item how to fix this?

I am new to react native and the problem i am facing is that when i
delete an item from the flatlist it deletes just fine but also does
update the item below it. It updates it into the item which was
deleted. What am i doing wrong?
CartScreen.js
This is my code for the cart screen
import React, { Component } from 'react';
import { View, Text, Picker, FlatList } from 'react-native';
import HeaderComp from '../components/HeaderComp'
import { Container, Content } from 'native-base';
import colors from '../assets/Colors';
import styles from '../assets/Styles';
import ButtonComp from '../components/ButtonComp';
import IconComp from '../components/IconComp'
import RowCartComp from '../components/RowCartComp';
class CartPage extends Component {
constructor(props) {
super(props);
this.state = {
cartList: [
{ name: 'Sub Item 1', image: require('../images/1.jpeg'), price: 100, remainingQty: 1 },
{ name: 'Sub Item 2', image: require('../images/2.jpeg'), price: 200, remainingQty: 2 },
{ name: 'Sub Item 3', image: require('../images/3.jpeg'), price: 300, remainingQty: 3 },
{ name: 'Sub Item 4', image: require('../images/4.jpeg'), price: 400, remainingQty: 4 },
{ name: 'Sub Item 5', image: require('../images/5.jpeg'), price: 500, remainingQty: 5 },
{ name: 'Sub Item 6', image: require('../images/6.jpeg'), price: 600, remainingQty: 6 },
{ name: 'Sub Item 7', image: require('../images/7.jpeg'), price: 700, remainingQty: 7 },
{ name: 'Sub Item 8', image: require('../images/8.jpeg'), price: 800, remainingQty: 8 },
{ name: 'Sub Item 9', image: require('../images/9.jpeg'), price: 900, remainingQty: 9 },
{ name: 'Sub Item 10', image: require('../images/10.jpeg'), price: 1000, remainingQty: 10 },
],
grandTotal: 0
}
}
componentWillMount() {
let total = 0;
for (let i = 0; i < this.state.cartList.length; i++) {
total = total + this.state.cartList[i].price;
}
this.setState({ grandTotal: total })
}
updateGrandTotal = (value, op) => {
if (op === 'add') {
this.setState({ grandTotal: this.state.grandTotal + value });
}
else if (op === 'sub') {
this.setState({ grandTotal: this.state.grandTotal - value })
}
}
deleteItem = (name) => {
this.setState(prevState => {
return {
cartList: prevState.cartList.filter(cartItem => {
return cartItem.name !== name;
})
}
})
}
render() {
return (
<Container>
<HeaderComp
headerTitle="CART"
showBackArrow={true}
showIcons={false}
backClick={
() => this.props.navigation.goBack()
} />
<Content>
<View style={styles.cartPickerStyle}>
<View style={{ flex: 0.1 }}>
<IconComp
name='location_icon'
color={colors.colorBlack}
size={30}
/>
</View>
<View style={{ flex: 0.9 }}>
<Picker
selectedValue={this.state.language}
style={{ height: 20 }}
onValueChange={(itemValue, itemIndex) =>
this.setState({ language: itemValue })
}>
<Picker.Item label="Address A" value="A" />
<Picker.Item label="Address B" value="B" />
<Picker.Item label="Address C" value="C" />
</Picker>
</View>
</View>
<FlatList
data={this.state.cartList}
renderItem={({ item }) =>
<RowCartComp
itemName={item.name.toUpperCase()}
itemImage={item.image}
itemPrice={item.price}
itemRemainingQty={item.remainingQty}
deleteItem={() => this.deleteItem(item.name)}
updateGrandTotal={this.updateGrandTotal}
/>
}
/>
<View style={{ flexDirection: 'row', alignItems: 'center', justifyContent: 'center' }}>
<View style={styles.cartSeparatorStyle} />
<Text style={styles.cashOnDeliveryTextStyle}>
{" Cash on delivery "}
</Text>
<View style={styles.cartSeparatorStyle} />
</View>
<View style={styles.cartGrandTotalViewStyle}>
<View style={{ flex: 0.6 }}>
<Text style={styles.cartTextStyle}>
{"Grand Total"}
</Text>
<Text style={styles.cartTextStyle}>
{"Delivery charges"}
</Text>
</View>
<View style={{ flex: 0.4, alignItems: 'flex-end' }}>
<Text style={styles.cartTextStyle}>
{this.state.grandTotal}
</Text>
<Text style={styles.cartTextStyle}>
{"+ 30"}
</Text>
<View style={{ height: 1, borderColor: colors.colorWhite, borderWidth: 1, width: '70%' }} />
<Text style={styles.cartTextStyle}>
{this.state.grandTotal + 30}
</Text>
</View>
</View>
<ButtonComp
buttonText={'Place order'}
buttonStyle={styles.cartButtonStyle}
textStyle={styles.cartButtonTextStyle} />
</Content>
</Container>
);
}
}
export default CartPage;
RowCartComp.js
This is my row item for the list used in the cart screen
import React, { Component } from 'react';
import { View, Image, Text, Alert, } from 'react-native';
import IconComp from '../components/IconComp'
import colors from '../assets/Colors'
class RowCartComp extends Component {
constructor(props) {
super(props);
this.state = {
qtyString: 1,
priceString: this.props.itemPrice,
remainingQty: this.props.itemRemainingQty
}
}
increaseQty = () => {
if (this.state.qtyString < this.props.itemRemainingQty) {
this.setState({
qtyString: this.state.qtyString + 1,
priceString: this.state.priceString + this.props.itemPrice,
remainingQty: this.state.remainingQty - 1
})
this.props.updateGrandTotal(this.props.itemPrice, 'add')
}
}
decreaseQty = () => {
if (this.state.qtyString != 1) {
this.setState({
qtyString: this.state.qtyString - 1,
priceString: this.state.priceString - this.props.itemPrice,
remainingQty: this.state.remainingQty + 1
})
this.props.updateGrandTotal(this.props.itemPrice, 'sub')
}
else {
Alert.alert(
'REMOVE ITEM?',
'Are you sure you want to remove ' + `${this.props.itemName.toLowerCase()}` + '?',
[
{ text: 'No' },
{ text: 'Yes', onPress: this.combinedFunction },
],
{ cancelable: true },
);
}
}
combinedFunction = () => {
this.props.deleteItem()
this.props.updateGrandTotal(this.props.itemPrice, 'sub')
}
render() {
return (
<View style={{ margin: 10, borderColor: colors.colorBlack, borderWidth: 1 }}>
<View style={{ flexDirection: 'row', margin: 10 }}>
<View>
<Image
style={{ height: 70, width: 70, borderRadius: 6, }}
// source={{ uri: imageURL }}
source={this.props.itemImage}
/>
</View>
<View style={{ flex: 0.6, flexWrap: 'wrap', justifyContent: 'center', marginLeft: 5 }}>
<Text style={{ fontSize: 20, fontWeight: 'bold', color: colors.colorBlack, marginBottom: 5 }}>
{this.props.itemName}
</Text>
</View>
<View style={{ flex: 0.4, alignItems: 'flex-end' }}>
<View style={{ flexDirection: 'row', alignItems: 'center' }}>
<IconComp
name='minus_icon'
color={colors.colorBlack}
size={20}
onPress={this.decreaseQty}
/>
<Text style={{ fontSize: 20, fontWeight: 'bold', color: colors.colorBlack, marginLeft: 10, marginRight: 10 }}>
{this.state.qtyString}
</Text>
<IconComp
name='plus_icon'
color={colors.colorBlack}
size={20}
onPress={this.increaseQty}
/>
</View>
</View>
</View>
<View style={{ flexDirection: 'row', position: 'absolute', bottom: 0, right: 5, alignItems: 'center' }}>
<Text style={{ fontSize: 14, fontWeight: 'bold', color: colors.colorPrimaryDark, marginRight: 15 }}>
{"Qty Left: " + (this.state.remainingQty - 1) }
</Text>
<Text style={{ fontSize: 20, fontWeight: 'bold', color: colors.colorBlack }}>
{"RS: " + `${this.state.priceString}`}
</Text>
</View>
</View>
);
}
}
export default RowCartComp;
Styles.js
This is the style file where i created the styles for the cart page.
import { StyleSheet } from 'react-native';
import colors from './Colors'
export default StyleSheet.create({
cartButtonStyle: {
margin: 10,
padding: 10,
backgroundColor: colors.colorPrimaryDark,
borderRadius: 26,
justifyContent: 'center',
alignItems: 'center',
elevation: 4, // Android
shadowColor: 'gray', // IOS
shadowOffset: { height: 1, width: 1 }, // IOS
shadowOpacity: 1, // IOS
shadowRadius: 1, //IOS
},
cartButtonTextStyle: {
fontSize: 24,
fontWeight: 'bold',
color: colors.colorBlack,
},
cartTextStyle: {
fontSize: 20,
color: colors.colorWhite,
fontWeight: 'bold',
margin: 5,
},
cashOnDeliveryTextStyle: {
fontSize: 18,
color: colors.colorBlack,
},
cartPickerStyle: {
margin: 10,
padding: 10,
borderRadius: 20,
borderWidth: 1,
borderColor: colors.colorBlack,
flexDirection: 'row',
alignItems: 'center'
},
cartSeparatorStyle: {
width: '30%',
height: 1,
borderStyle: 'dotted',
borderColor: colors.colorBlack,
borderWidth: 1,
borderRadius: 1
},
cartGrandTotalViewStyle: {
margin: 10,
backgroundColor: colors.colorPrimaryDark,
flexDirection: 'row',
padding: 5,
paddingTop: 10,
paddingBottom: 10
},
});
The icons i used are imported using icomoon app and i created a custom component for it.
The button i used i also created a custom component for it.
These are the screenshots of the problem i am facing.
When Sub Item 3 is deleted, Sub Item 4 take its properties like the quantity left and the price of Sub Item 3.
The key to this is using making your cartItem have a key property, or to set a keyextractor function on the FlatList. By doing so, react "knows" which item is deleted and can update the correct RowCartComp. If you forget to have key property (or don't have keyExtractor), react only has the index of the updated item and thus might re-use the wrong component of your array.
Check the FlatList documentation for more information.
The code you posted however, actually contains kind of a React anti-pattern: you're copying props into the state of your child component RowCartComp. This makes managing updates and diffing in the RowCartComp harder. It would be better to lift the increase and decrease functions into the parent container. That way all manipulation logic resides in CartScreen and the RowCartComp can simply be a functional component and nothing can go out-of-sync.
I turned the RowCartComp into a function component accepting only some props and having no internal state. It accepts all data and handler functions from the parent
RowCartComp.js
import React, { Component } from "react";
import { View, Image, Text, Alert } from "react-native";
import IconComp from "../components/IconComp";
import colors from "../assets/Colors";
// this is now a functional component receiving
// 1. the entire cart item including qty property
// 2. handler to delete
// 3. handlers to increase/decrease the quantity
const RowCartComp = ({ item, deleteItem, increaseQty, decreaseQty }) => {
return (
<View
style={{ margin: 10, borderColor: colors.colorBlack, borderWidth: 1 }}
>
<View style={{ flexDirection: "row", margin: 10 }}>
<View>
<Image
style={{ height: 70, width: 70, borderRadius: 6 }}
source={itemImage}
/>
</View>
<View
style={{
flex: 0.6,
flexWrap: "wrap",
justifyContent: "center",
marginLeft: 5
}}
>
<Text
style={{
fontSize: 20,
fontWeight: "bold",
color: colors.colorBlack,
marginBottom: 5
}}
>
{item.name}
</Text>
</View>
<View style={{ flex: 0.4, alignItems: "flex-end" }}>
<View style={{ flexDirection: "row", alignItems: "center" }}>
<IconComp
name="minus_icon"
color={colors.colorBlack}
size={20}
onPress={decreaseQty}
/>
<Text
style={{
fontSize: 20,
fontWeight: "bold",
color: colors.colorBlack,
marginLeft: 10,
marginRight: 10
}}
>
{item.qty.toString()}
</Text>
<IconComp
name="plus_icon"
color={colors.colorBlack}
size={20}
onPress={increaseQty}
/>
</View>
</View>
</View>
<View
style={{
flexDirection: "row",
position: "absolute",
bottom: 0,
right: 5,
alignItems: "center"
}}
>
<Text
style={{
fontSize: 14,
fontWeight: "bold",
color: colors.colorPrimaryDark,
marginRight: 15
}}
>
{"Qty Left: " + (item.remainingQty - item.qty)}
</Text>
<Text
style={{ fontSize: 20, fontWeight: "bold", color: colors.colorBlack }}
>
{"RS: " + `${item.price}`}
</Text>
</View>
</View>
);
};
export default RowCartComp;
Additionally I adjusted the CartPage.js component to
calculate the grand total on every render, it is a consequence of the current cart list
the cart items all have a quantity and an id property so the flatlist can work
have a handler that can increase of decrease the quantity of a cart item. This is then passed to the individual items
CartPage.js
import React, { Component } from 'react';
import { View, Text, Picker, FlatList } from 'react-native';
import HeaderComp from '../components/HeaderComp'
import { Container, Content } from 'native-base';
import colors from '../assets/Colors';
import styles from '../assets/Styles';
import ButtonComp from '../components/ButtonComp';
import IconComp from '../components/IconComp'
import RowCartComp from '../components/RowCartComp';
class CartPage extends Component {
constructor(props) {
super(props);
this.state = {
cartList: [
{ id: 1, name: 'Sub Item 1', image: require('../images/1.jpeg'), price: 100, remainingQty: 1, qty: 1 },
{ id: 2, name: 'Sub Item 2', image: require('../images/2.jpeg'), price: 200, remainingQty: 2, qty: 1 },
{ id: 3, name: 'Sub Item 3', image: require('../images/3.jpeg'), price: 300, remainingQty: 3, qty: 1 },
{ id: 4, name: 'Sub Item 4', image: require('../images/4.jpeg'), price: 400, remainingQty: 4, qty: 1 },
{ id: 5, name: 'Sub Item 5', image: require('../images/5.jpeg'), price: 500, remainingQty: 5, qty: 1 },
{ id: 6, name: 'Sub Item 6', image: require('../images/6.jpeg'), price: 600, remainingQty: 6, qty: 1 },
{ id: 7, name: 'Sub Item 7', image: require('../images/7.jpeg'), price: 700, remainingQty: 7, qty: 1 },
{ id: 8, name: 'Sub Item 8', image: require('../images/8.jpeg'), price: 800, remainingQty: 8, qty: 1 },
{ id: 9, name: 'Sub Item 9', image: require('../images/9.jpeg'), price: 900, remainingQty: 9, qty: 1 },
{ id: 10, name: 'Sub Item 10', image: require('../images/10.jpeg'), price: 1000, remainingQty: 10, qty: 1 },
],
}
}
// we can just calculate this every render
calculateGrandTotal () => {
let total = 0;
this.state.cartList.forEach(item => {
const itemTotal =item.qty * item.price;
total += itemTotal;
});
return total;
};
adjustQuantity = (id, diff) => {
const index = this.state.cartList.findIndex(ci => ci.id === id);
const item = this.state.cartList[index];
const newItem = {
...this.state.cartList[index],
qty: item.qty + diff
};
// don't go above remaining quantity
if (newItem.qty > newItem.remainingQty) {
return;
}
// don't go below 0
if (newItem.qty < 0) {
return;
}
// copy list and insert new item with adjusted quantity
const newCartList = [...this.state.cartList];
newCartList.splice(index, 1, newItem)
this.setState({
cartList: newCartList,
})
};
deleteItem = (id) => {
this.setState(prevState => {
return {
cartList: prevState.cartList.filter(cartItem => {
return cartItem.id !== id;
})
}
})
}
render() {
// grand total is calculated on every render, as it is
// a consequence of the current cartList
const grandTotal = this.calculateGrandTotal();
return (
<Container>
<HeaderComp
headerTitle="CART"
showBackArrow={true}
showIcons={false}
backClick={
() => this.props.navigation.goBack()
} />
<Content>
<View style={styles.cartPickerStyle}>
<View style={{ flex: 0.1 }}>
<IconComp
name='location_icon'
color={colors.colorBlack}
size={30}
/>
</View>
<View style={{ flex: 0.9 }}>
<Picker
selectedValue={this.state.language}
style={{ height: 20 }}
onValueChange={(itemValue, itemIndex) =>
this.setState({ language: itemValue })
}>
<Picker.Item label="Address A" value="A" />
<Picker.Item label="Address B" value="B" />
<Picker.Item label="Address C" value="C" />
</Picker>
</View>
</View>
<FlatList
data={this.state.cartList}
keyExtractor={item => `cart_${item.id}`}
renderItem={({ item }) =>
<RowCartComp
item={item}
deleteItem={() => this.deleteItem(item.id)}
increaseQty={() => this.adjustQuantity(item.id, +1)}
decreaseQty={() => this.adjustQuantity(item.id, -1)}
/>
}
/>
<View style={{ flexDirection: 'row', alignItems: 'center', justifyContent: 'center' }}>
<View style={styles.cartSeparatorStyle} />
<Text style={styles.cashOnDeliveryTextStyle}>
{" Cash on delivery "}
</Text>
<View style={styles.cartSeparatorStyle} />
</View>
<View style={styles.cartGrandTotalViewStyle}>
<View style={{ flex: 0.6 }}>
<Text style={styles.cartTextStyle}>
{"Grand Total"}
</Text>
<Text style={styles.cartTextStyle}>
{"Delivery charges"}
</Text>
</View>
<View style={{ flex: 0.4, alignItems: 'flex-end' }}>
<Text style={styles.cartTextStyle}>
{grandTotal}
</Text>
<Text style={styles.cartTextStyle}>
{"+ 30"}
</Text>
<View style={{ height: 1, borderColor: colors.colorWhite, borderWidth: 1, width: '70%' }} />
<Text style={styles.cartTextStyle}>
{grandTotal + 30}
</Text>
</View>
</View>
<ButtonComp
buttonText={'Place order'}
buttonStyle={styles.cartButtonStyle}
textStyle={styles.cartButtonTextStyle} />
</Content>
</Container>
);
}
}
export default CartPage;
Hope this helps.

React Native: Display FlatList data in Modal

I have a react native flat list that renders some data from a Wordpress website using wp rest api. The flat list is displaying the post correctly, and when clicked, it opens the modal, but I am having some trouble pushing the state to the modal.
Currently, when the modal opens, it shows the same (last post/item) for every item in the flat list. Any suggestions? Any help appreciated.
import React, { Component } from 'react';
import {
Image, Dimensions, View, ActivityIndicator, TouchableOpacity, TouchableHighlight,
WebView, ScrollView, StyleSheet, ImageBackground, FlatList, Text
} from 'react-native';
import Moment from 'moment';
import HTML from 'react-native-render-html';
import Modal from "react-native-modal";
export default class LatestNews extends Component {
constructor(props) {
super(props);
this.state = {
isModalVisible: false,
isLoading: true,
posts: [],
id: null,
};
}
componentDidMount() {
fetch(`http://mywebsite.com/wp-json/wp/v2/posts/?_embed&categories=113`)
.then((response) => response.json())
.then((responseJson) => {
this.setState({
isLoading: false,
posts: responseJson,
})
})
.catch((error) => {
console.error(error);
});
}
_toggleModal = () =>
this.setState({
isModalVisible: !this.state.isModalVisible,
});
_renderItem = ({item}) => {
return (
<TouchableOpacity onPress={() => this._onPressItem(item.id)} key={item.id}>
<View>
{item._embedded['wp:featuredmedia'].filter(
element => element.id == item.featured_media
).map((subitem, index) => (
<View style={{
margin: '5%',
borderWidth: 1,
borderColor: '#d8d8d8',
borderRadius: 10,
shadowColor: '#000',
shadowOffset: { width: 0, height: 5 },
shadowOpacity: 0.2,
shadowRadius: 8,
elevation: 1,
}}>
<ImageBackground
style={styles.news}
source={{ uri: subitem.media_details.sizes.medium.source_url }}
key={item.id}>
<View style={styles.itemTitle}>
<Text style={{ fontSize: 16, fontWeight: 'bold' }}>
{item.title.rendered}
</Text>
</View>
</ImageBackground>
</View>
))}
</View>
</TouchableOpacity>
)
};
_onPressItem(id) {
this.setState({
isModalVisible: true,
id: id,
});
};
render() {
if (this.state.isLoading == true) {
return (
<View style={{ flex: 1, flexDirection: 'column', justifyContent: 'center', alignItems: 'center', }}>
<ActivityIndicator size="large" color="#1C97F7" />
</View>
)
}
else {
Moment.locale('en');
return (
<View>
{this.state.posts.map((item, index) => (
<Modal isVisible={this.state.isModalVisible} id={this.state.id}>
{item._embedded['wp:featuredmedia'].filter(
element => element.id == item.featured_media
).map((subitem, index) => (
<ScrollView style={
{ flex: 1, backgroundColor: 'white', padding: 20, paddingBottom: 40,}
}>
<ImageBackground
style={styles.news}
source={{ uri: subitem.media_details.sizes.medium.source_url }}
key={item.id} />
<TouchableOpacity onPress={this._toggleModal}>
<Text>Hide me!</Text>
</TouchableOpacity>
<HTML
tagsStyles={{
body: {fontSize: 16, paddingBottom: 20,},
p: {fontSize: 16, fontWeight: "normal", marginTop: 10, marginBottom: 20},
strong: {fontSize: 20,},
blockquote: {fontSize: 20},
a: {fontSize: 16, color: "#0044e2"},
em: {fontSize: 20,},
img: {height: 250, width: 350},
}}
key={item.id}
styleName="paper md-gutter multiline"
html={item.content.rendered}
imagesMaxWidth={Dimensions.get('window').width * .9}
ignoredStyles={['width', 'height', 'video']}
/>
</ScrollView>
))}
</Modal>
))}
<FlatList
data={this.state.posts}
renderItem={this._renderItem}
keyExtractor={(item, index) => index}
/>
</View>
)
}
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#fff',
paddingTop: 0,
},
h1: {
color: 'black',
fontSize: 24,
paddingTop: 20,
fontWeight: 'bold',
},
h2: {
color: 'black',
fontSize: 24,
paddingTop: 20,
fontWeight: 'bold',
},
h3: {
fontSize: 13,
},
button: {
width: '45%',
margin: 5,
backgroundColor: '#492661',
padding: 8,
height: 36,
borderRadius: 18,
},
buttonGrey: {
width: '45%',
margin: 5,
backgroundColor: '#353535',
padding: 8,
height: 36,
borderRadius: 18,
},
buttonText: {
color: 'black',
alignSelf: 'center',
},
highlight: {
backgroundColor: '#f5f5f5',
borderRadius: 50,
width: 100,
height: 100,
marginRight: 20,
alignItems: 'center',
justifyContent: 'center',
borderColor: 'gold',
borderWidth: 0,
},
news: {
backgroundColor: '#f5f5f5',
borderRadius: 10,
width: '100%',
height: 200,
overflow: 'hidden',
},
hero: {
backgroundColor: '#492661',
width: '110%',
height: 260,
alignSelf: 'center',
marginTop: 0,
overflow: 'hidden'
},
itemTitle: {
backgroundColor: 'rgba(255,255,255,0.9)',
paddingVertical: 10,
position: 'absolute',
bottom: 0,
right: 0,
width: '100%',
paddingHorizontal: 10,
},
});
In FlatList, this is the issue it can't re-render again if dataModel is being there. For this You can use this :
in FlatList there is a propsTypes: ExtraData={} in this you should add a new boolean state, and wherever you again add the data in flatlist . set the state for that boolean key , that would help you :
<FlatList
data={this.state.posts}
renderItem={this._renderItem}
keyExtractor={(item, index) => index}
extraData={this.state.extraData}
/>
where you want add flatList data again add this line:
this.setState({extraData:!this.state.extraData})
by this line render method run again , and you will find a new update records.
Use this, this help me.

react-native-deck-swiper error is TypeError: undefined is not an object (evaluating 'cards.length')

Created by referring to https://snack.expo.io/rJBRhOLU-
const cardOne = require("../../image/doginfo-1.png");
const cardTwo = require("../../image/doginfo-2.png");
const cardThree = require("../../image/doginfo-3.png");
const cardFour = require("../../image/doginfo-4.png");
class AdvancedDeck extends Component {
constructor(props) {
super(props);
this.sate = {
cardIndex: 0,
swipedAllCards: false,
swipeDirection: "",
cards: [
{
text: "Card One",
name: "One",
image: cardOne
},
{
text: "Card Two",
name: "Two",
image: cardTwo
},
{
text: "Card Three",
name: "Three",
image: cardThree
},
{
text: "Card Four",
name: "Four",
image: cardFour
}
]
};
}
renderCard = (card, index) => {
return (
<Card style={{ elevation: 3 }}>
<CardItem>
<Left>
<Thumbnail source={card.image} />
<Body>
<Text>{card.text}</Text>
<Text note>NativeBase</Text>
</Body>
</Left>
</CardItem>
<CardItem cardBody>
<Image
style={{
resizeMode: "cover",
width: null,
flex: 1,
height: 300
}}
source={card.image}
/>
</CardItem>
<CardItem>
<IconNB name={"ios-heart"} style={{ color: "#ED4A6A" }} />
<Text>
{card.name}-{index}
</Text>
</CardItem>
</Card>
);
};
onSwipedAllCards = () => {
this.setState({
swipedAllCards: true
});
};
swipeLeft = () => {
this.swiper.swipeLeft();
};
render() {
return (
<Container style={styles.container}>
<Header>
<Left>
<Button transparent onPress={() => this.props.navigation.goBack()}>
<Icon name="arrow-back" />
</Button>
</Left>
<Body>
<Title>Advanced Deck Swiper</Title>
</Body>
<Right />
</Header>
<View style={{ flex: 1, padding: 12 }}>
<Swiper
ref={swiper => {
this.swiper = swiper;
}}
onSwiped={this.onSwiped}
onSwipedLeft={() => this.onSwiped("left")}
onSwipedRight={() => this.onSwiped("right")}
onSwipedTop={() => this.onSwiped("top")}
onSwipedBottom={() => this.onSwiped("bottom")}
onTapCard={this.swipeLeft}
cards={this.props.cards}
cardIndex={this.props.cardIndex}
cardVerticalMargin={80}
renderCard={this.renderCard}
onSwipedAll={this.onSwipedAllCards}
showSecondCard={false}
stackSize={3}
stackSeparation={15}
overlayLabels={{
bottom: {
title: "BLEAH",
style: {
label: {
backgroundColor: "black",
borderColor: "black",
color: "white",
borderWidth: 1
},
wrapper: {
flexDirection: "column",
alignItems: "center",
justifyContent: "center"
}
}
},
left: {
title: "NOPE",
style: {
label: {
backgroundColor: "black",
borderColor: "black",
color: "white",
borderWidth: 1
},
wrapper: {
flexDirection: "column",
alignItems: "flex-end",
justifyContent: "flex-start",
marginTop: 30,
marginLeft: -30
}
}
},
right: {
title: "LIKE",
style: {
label: {
backgroundColor: "black",
borderColor: "black",
color: "white",
borderWidth: 1
},
wrapper: {
flexDirection: "column",
alignItems: "flex-start",
justifyContent: "flex-start",
marginTop: 30,
marginLeft: 30
}
}
},
top: {
title: "SUPER LIKE",
style: {
label: {
backgroundColor: "black",
borderColor: "black",
color: "white",
borderWidth: 1
},
wrapper: {
flexDirection: "column",
alignItems: "center",
justifyContent: "center"
}
}
}
}}
animateOverlayLabelsOpacity
animateCardOpacity
swipeBackCard
/>
</View>
<View
style={{
flexDirection: "row",
flex: 1,
position: "absolute",
bottom: 50,
left: 0,
right: 0,
justifyContent: "space-between",
padding: 15
}}
>
<Button
style={{ backgroundColor: "black" }}
onPress={() => this.swiper.swipeBack()}
title="Swipe Back"
>
<Icon name="arrow-back" />
<Text>Swipe Left</Text>
</Button>
<Button iconRight onPress={() => this._deckSwiper._root.swipeRight()}>
<Text>Swipe Right</Text>
<Icon name="arrow-forward" />
</Button>
</View>
</Container>
);
}
}
export default AdvancedDeck;
How can I fix it?
I changed the code to contact-native-check-swiper to write back button because it did not turn into a back button while writing the existing default-base checkswiper.
Any answer is welcome. Please help me a lot.
The problem is with
<Swiper
...
cards={this.props.cards}
...
You've defined the cards in this.state = { cards: ... } instead

How to align one component to left and other to right (end of page) react native?

I'm making an app in React Native and I want align a circle with the end of page.
I want to make this:
But it's currently like this and only stays this way:
The complete view:
[
I already tried alignSelf, justifyContent and others but it doesn't work.
I tested this: How to align 2 react native elements, 1 being in the center and 1 on the beginning
But it won't work.
My code:
const ListProductsHeader = () => (
<View>
<View style={style.containerInfo}>
<View style={style.circle} />
<View>
<Text style={style.unityName}>SUPERMERCADO MACCARTNEY</Text>
<Text style={style.subInfo}>Categoria: Mercado</Text>
<Text style={style.subInfo}>Pedido Nº: 1245</Text>
</View>
</View>
<View style={style.containerProducts}>
<Text style={style.productName}>1x 42 - Coca Cola 2L</Text>
<View style={style.minus}></View>
</View>
</View>
);
CSS:
containerProducts:{
paddingTop: 40,
paddingLeft: 15,
flexDirection: 'row',
},
productName: {
alignSelf: 'flex-start',
},
minus:{
width: 20,
height: 20,
borderRadius: 20/2,
backgroundColor: 'red',
},
containerInfo:{
paddingTop:15,
flexDirection:'row',
paddingLeft: 15,
},
unityName:{
fontWeight: 'bold',
paddingLeft: 15,
},
subInfo:{
color: 'gray',
paddingLeft: 15,
},
circle: {
width: 50,
height: 50,
borderRadius: 50/2,
backgroundColor: 'red',
justifyContent: 'flex-end',
},
Lkke to suggest one thing that can help you with this problem
what you need to do is. Everthing is correct except the main view css
<View style={flexDirection:'row',justifyContent : 'space-between'}>
<View style={style.circle} />
<View>
<Text style={style.unityName}>SUPERMERCADO MACCARTNEY</Text>
<Text style={style.subInfo}>Categoria: Mercado</Text>
<Text style={style.subInfo}>Pedido Nº: 1245</Text>
</View>
</View>
<View style={style.containerProducts}>
<Text style={style.productName}>1x 42 - Coca Cola 2L</Text>
<View style={style.minus}></View>
</View>
try this may be it can help you
containerProducts: {
paddingTop: 40,
paddingLeft: 15,
flexDirection: 'row',
justifyContent: 'space-between',
},
Fully Customisable chat in React Native
import React, {Component} from 'react';
import {
Text,
StyleSheet,
View,
TextInput,
TouchableOpacity,
SafeAreaView,
FlatList,
} from 'react-native';
export default class CustomChatScreen extends Component {
state = {
messages: [
{
msg: 'Heloo',
id: Math.random(),
token: '',
email: '',
type: 'server',
},
{
msg: 'Server Message',
id: Math.random(),
token: '',
email: '',
type: 'server',
},
],
value: '',
};
sendMessageToServer = () => {
if (this.state.value !== '') {
let payload = {
msg: this.state.value,
id: Math.random(),
token: '',
email: '',
type: 'client',
};
let mydata = this.state.messages;
mydata.push(payload);
this.setState({
messages: mydata,
value: '',
});
}
};
renderFlatListItem = rowData => {
return (
<View style={styles.flatListContainerStyle}>
{rowData.item.type === 'client' ? (
<View style={styles.clientMsgStyle}>
<Text>{rowData.item.msg}</Text>
</View>
) : (
<View style={styles.serverMsgStyle}>
<Text>{rowData.item.msg}</Text>
</View>
)}
</View>
);
};
render() {
return (
<SafeAreaView style={styles.container}>
<FlatList
data={this.state.messages}
keyExtractor={(item, index) => index.toString()}
renderItem={this.renderFlatListItem}
/>
<View style={styles.sendMessageConatinerStyle}>
<TextInput
style={styles.sendMsgTextInputStyle}
value={this.state.value}
placeholder = {"please type here!"}
placeholderTextColor = {"#000"}
onChangeText={val => this.setState({value: val})}></TextInput>
<TouchableOpacity
style={styles.sendMsgButtonStyle}
onPress={this.sendMessageToServer}>
<Text>Send Message</Text>
</TouchableOpacity>
</View>
</SafeAreaView>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
},
sendMessageConatinerStyle: {
width: '100%',
height: 60,
position: 'absolute',
bottom: 0,
left: 0,
right: 0,
backgroundColor: 'white',
flexDirection: 'row',
},
sendMsgTextInputStyle: {
backgroundColor: '#e0f2f1',
flex: 0.8,
borderTopLeftRadius: 62.5,
borderBottomLeftRadius: 62.5,
padding: 20,
},
sendMsgButtonStyle: {
flex: 0.2,
backgroundColor: '#80cbc4',
borderBottomRightRadius: 62.5,
borderTopRightRadius: 62.5,
fontSize: 18,
justifyContent: 'center',
alignItems: 'center',
},
flatListContainerStyle: {
backgroundColor: '#e0f7fa',
marginTop: 10,
},
clientMsgStyle: {
backgroundColor: '#ffab91',
borderRadius: 20,
padding: 15,
alignSelf: 'flex-end',
},
serverMsgStyle: {
backgroundColor: '#4fc3f7',
borderRadius: 20,
padding: 15,
alignSelf: 'flex-start',
},
});