React Native redux 状态数组更新导致未定义错误

React Native redux state array update causes undefined error

我正在构建一个 RN 应用程序,我最近才学习 REDUX 并将其应用到我的应用程序中。我的移动应用程序中有购物车功能。在一个屏幕上,用户可以将商品添加到购物车。完成后,他们可以单击购物车图标查看完整的购物车(新屏幕)。

下面显示的是我的购物车屏幕的代码。

import React, { useState, useEffect } from "react";
import { StyleSheet, SafeAreaView } from "react-native";
import {
  Icon,
  Layout,
  Text,
  TopNavigation,
  TopNavigationAction,
  Divider,
  List,
  ListItem,
  Button,
  useTheme,
} from "@ui-kitten/components";
import * as AppConstants from "../constants/constants";
import { useDispatch, useSelector } from "react-redux";
import { cartItemRemoved } from "../store/shoppingCart";

const CartScreen = ({ navigation }) => {
  const theme = useTheme();
  const dispatch = useDispatch();
  const cartData = useSelector((state) => state.shoppingCart.cart);

  const BackIcon = (props) => <Icon {...props} name="arrow-back" />;
  const TrashIcon = (props) => <Icon {...props} name="trash-2" />;

  const BackAction = () => (
    <TopNavigationAction icon={BackIcon} onPress={() => navigation.goBack()} />
  );

  useEffect(() => {}, []);

  const renderItemAccessory = (item) => {
    return (
      <Button
        status="danger"
        accessoryLeft={TrashIcon}
        size="tiny"
        onPress={() => {
          alert("You selected: " + item.serviceName + item.serviceId);
          dispatch(cartItemRemoved(item.serviceId));
        }}
      >
        Delete
      </Button>
    );
  };

  const renderItem = ({ item }) => (
    <ListItem
      title={`${item.serviceName}`}
      description={`${item.price}`}
      accessoryRight={() => renderItemAccessory(item)}
    />
  );

  return (
    <SafeAreaView style={{ flex: 1 }}>
      <TopNavigation
        title={AppConstants.TITLE_Cart}
        subtitle={AppConstants.APP_SLOGAN}
        alignment="center"
        accessoryLeft={() => BackAction()}
      />
      <Divider />
      <Layout style={styles.container}>
        {cartData.length > 0 ? (
          <>
            <List
              data={cartData}
              ItemSeparatorComponent={Divider}
              renderItem={renderItem}
            />
            <Button onPress={() => {}}>Send</Button>
          </>
        ) : (
          <Text style={styles.text} category="h1">
            Cart is empty.
          </Text>
        )}
      </Layout>
    </SafeAreaView>
  );
};

const styles = StyleSheet.create({
  container: {
    maxHeight: 300,
  },
  text: {
    textAlign: "center",
    padding: 10,
  },
});

export default CartScreen;

首次打开此屏幕时,购物车中的商品会显示,没有任何错误或警告。单击删除按钮后,我可以看到我的 REDUX 状态数组已更新,该项目已从中删除。但随后我的应用程序崩溃并显示以下错误消息。

TypeError: undefined is not an object (evaluating 'cartData.length')

This error is located at:
    in CartScreen (at SceneView.tsx:122)
    in StaticContainer
    in StaticContainer (at SceneView.tsx:115)
    in EnsureSingleNavigator (at SceneView.tsx:114)
    in SceneView (at useDescriptors.tsx:153)
    in RCTView (at View.js:34)
    in View (at ResourceSavingScene.tsx:68)
    in RCTView (at View.js:34)
    in View (at ResourceSavingScene.tsx:63)
    in ResourceSavingScene (at DrawerView.tsx:183)
    in RCTView (at View.js:34)
    in View (at src/index.native.js:134)
    in ScreenContainer (at DrawerView.tsx:162)
    in RCTView (at View.js:34)
    in View (at Drawer.tsx:645)
    in RCTView (at View.js:34)
    in View (at createAnimatedComponent.js:240)
    in AnimatedComponent(View) (at Drawer.tsx:638)
    in RCTView (at View.js:34)
    in View (at createAnimatedComponent.js:240)
    in AnimatedComponent(View) (at Drawer.tsx:628)
    in PanGestureHandler (at GestureHandlerNative.tsx:13)
    in PanGestureHandler (at Drawer.tsx:619)
    in DrawerView (at DrawerView.tsx:215)
    in SafeAreaProviderCompat (at DrawerView.tsx:213)
    in RCTView (at View.js:34)
    in View (at DrawerView.tsx:212)
    in DrawerView (at createDrawerNavigator.tsx:47)
    in DrawerNavigator (at HomeStack.js:13)
    in HomeStack (at SceneView.tsx:122)
    in StaticContainer
    in StaticContainer (at SceneView.tsx:115)
    in EnsureSingleNavigator (at SceneView.tsx:114)
    in SceneView (at useDescriptors.tsx:153)
    in RCTView (at View.js:34)
    in View (at CardContainer.tsx:245)
    in RCTView (at View.js:34)
    in View (at CardContainer.tsx:244)
    in RCTView (at View.js:34)
    in View (at CardSheet.tsx:33)
    in ForwardRef(CardSheet) (at Card.tsx:573)
    in RCTView (at View.js:34)
    in View (at createAnimatedComponent.js:165)
    in AnimatedComponent (at createAnimatedComponent.js:215)
    in ForwardRef(AnimatedComponentWrapper) (at Card.tsx:555)
    in PanGestureHandler (at GestureHandlerNative.tsx:13)
    in PanGestureHandler (at Card.tsx:549)
    in RCTView (at View.js:34)
    in View (at createAnimatedComponent.js:165)
    in AnimatedComponent (at createAnimatedComponent.js:215)
    in ForwardRef(AnimatedComponentWrapper) (at Card.tsx:544)
    in RCTView (at View.js:34)
    in View (at Card.tsx:538)
    in Card (at CardContainer.tsx:206)
    in CardContainer (at CardStack.tsx:620)
    in RCTView (at View.js:34)
    in View (at Screens.tsx:84)
    in MaybeScreen (at CardStack.tsx:613)
    in RCTView (at View.js:34)
    in View (at Screens.tsx:54)
    in MaybeScreenContainer (at CardStack.tsx:495)
    in CardStack (at StackView.tsx:462)
    in KeyboardManager (at StackView.tsx:458)
    in RNCSafeAreaProvider (at SafeAreaContext.tsx:74)
    in SafeAreaProvider (at SafeAreaProviderCompat.tsx:42)
    in SafeAreaProviderCompat (at StackView.tsx:455)
    in RCTView (at View.js:34)
    in View (at StackView.tsx:454)
    in StackView (at createStackNavigator.tsx:87)
    in StackNavigator (at navigation/index.js:21)
    in EnsureSingleNavigator (at BaseNavigationContainer.tsx:409)
    in ForwardRef(BaseNavigationContainer) (at NavigationContainer.tsx:91)
    in ThemeProvider (at NavigationContainer.tsx:90)
    in ForwardRef(NavigationContainer) (at navigation/index.js:20)
    in ServiceNavigation (created by Connect(ServiceNavigation))
    in Connect(ServiceNavigation) (at App.js:46)
    in RCTView (at View.js:34)
    in View (created by ModalPanel)
    in ModalPanel (created by ApplicationProvider)
    in ThemeProvider (created by StyleProvider)
    in MappingProvider (created by StyleProvider)
    in StyleProvider (created by ApplicationProvider)
    in ApplicationProvider (at App.js:45)
    in Provider (at App.js:43)
    in App (created by ExpoRoot)
    in RootErrorBoundary (created by ExpoRoot)
    in ExpoRoot (at renderApplication.js:45)
    in RCTView (at View.js:34)
    in View (at AppContainer.js:106)
    in RCTView (at View.js:34)
    in View (at AppContainer.js:132)
    in AppContainer (at renderApplication.js:39)

再往下我也收到这个错误信息

Warning: Can't perform a React state update on an unmounted component. This is a no-op, but it indicates a memory leak in your application. To fix, cancel all subscriptions and asynchronous tasks in a useEffect cleanup function.
at node_modules\react-native\Libraries\LogBox\LogBox.js:173:8 in registerError

这是我的 REDUX reducer 中的代码

//================================================
// Action types
//================================================
const CART_ITEM_ADDED = "cartItemAdded";
const CART_ITEM_REMOVED = "cartItemRemoved";

//================================================
// Actions - This is also known as action creators
//================================================
export const cartItemAdded = (
  serviceId,
  quantity,
  description,
  serviceName,
  price
) => ({
  type: CART_ITEM_ADDED,
  payload: {
    serviceId,
    quantity,
    description,
    serviceName,
    price,
  },
});

export const cartItemRemoved = (serviceId) => ({
  type: CART_ITEM_REMOVED,
  payload: {
    serviceId,
  },
});

//================================================
// Reducer
//================================================

const initialState = {
  cart: [],
};

export default function shoppingCartReducer(state = initialState, action) {
  switch (action.type) {
    case CART_ITEM_ADDED:
      return {
        ...state,
        cart: [...state.cart, action.payload],
      };

    case CART_ITEM_REMOVED:
      return state.cart.filter(
        (service) => service.serviceId !== action.payload.serviceId
      );

    default:
      return state;
  }
}

如果有人可以帮助我理解我在这里缺少什么?

问题出在你的reducers

case CART_ITEM_REMOVED:
      return state.cart.filter(
        (service) => service.serviceId !== action.payload.serviceId
      );

你已经改变了所有的状态,一定是

case CART_ITEM_REMOVED:
      return {
       ...state,
       cart: state.cart.filter((service) => service.serviceId !== action.payload.serviceId)
       };