我的行项目自动更新为已删除项目,如何解决此问题?

时间:2019-05-09 06:25:45

标签: react-native

  

我是新来的本地人,我面临的问题是当我   从单位列表中删除一个项目,它删除就可以了,但也可以   更新它下面的项目。它将其更新为   已删除。我在做什么错了?

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的剩余数量和价格。

1 个答案:

答案 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 组件调整为

  1. 计算每次渲染的总计,这是当前购物车列表的结果
  2. 购物车中的所有商品均具有数量和id属性,因此列表可以使用
  3. 有一个处理程序,可以增加减少购物车项目的数量。然后将其传递给各个项目

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;

希望这会有所帮助。