我是新来的本地人,我面临的问题是当我 从单位列表中删除一个项目,它删除就可以了,但也可以 更新它下面的项目。它将其更新为 已删除。我在做什么错了?
CartScreen.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: [
{ 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
这是我在购物车屏幕上使用的列表的行项
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
这是样式文件,我在其中创建了购物车页面的样式。 从'react-native'导入{StyleSheet}; 从“ ./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
},
});
我使用的图标是使用icomoon应用程序导入的,我为此创建了一个自定义组件。 我使用的按钮还为它创建了一个自定义组件。
这些是我面临的问题的屏幕截图。
子项目3删除后,子项目4将具有其属性,例如子项目3的剩余数量和价格。
答案 0 :(得分:1)
关键是要使您的cartItem
具有key
属性,或在FlatList上设置keyextractor
函数。这样,可以“知道”删除了哪个项目,并可以更新正确的RowCartComp
。如果您忘记拥有key
属性(或没有keyExtractor
),则react仅具有更新项的索引,因此可能会重用数组的错误组件。
查看FlatList文档以了解更多信息。
但是,您发布的代码实际上包含一种React反模式:您正在将props复制到子组件RowCartComp
的状态。这使得管理更新和扩散RowCartComp
变得更加困难。最好将增加和减少功能提升到父容器中。这样,所有操纵逻辑都驻留在CartScreen
中,而RowCartComp
可以只是一个功能组件,没有任何事物可以不同步。
我将RowCartComp变成了仅接受一些道具并且没有内部状态的功能组件。它接受父级的所有数据和处理程序功能
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;
另外,我将 CartPage.js 组件调整为
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;
希望这会有所帮助。