简体   繁体   English

React Native redux state 数组更新导致未定义的错误

[英]React Native redux state array update causes undefined error

I'm building a RN app and I just recently learned REDUX and applied it into my app.我正在构建一个 RN 应用程序,我最近才学习了 REDUX 并将其应用到我的应用程序中。 I have a shopping cart feature in my mobile app.我的移动应用程序中有购物车功能。 On one screen the user can add items to the cart.在一个屏幕上,用户可以将商品添加到购物车。 Then when they are done they can click the cart icon to view the full cart (new screen).然后,当他们完成后,他们可以单击购物车图标来查看完整的购物车(新屏幕)。

Shown below is the code for my cart screen.下面显示的是我的购物车屏幕的代码。

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;

When this screen is first opened the items in the cart are displayed without any errors or warnings.首次打开此屏幕时,购物车中的项目会显示,没有任何错误或警告。 Soon as I click the delete button, I can see that my REDUX state array was updated, the item was removed from it.单击删除按钮后,我可以看到我的 REDUX state 数组已更新,该项目已从中删除。 But then my app crashes with the error message below.但是随后我的应用程序崩溃并显示以下错误消息。

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)

Further down I also get this error message再往下,我也收到此错误消息

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

Here is the code in my REDUX reducer这是我的 REDUX 减速机中的代码

//================================================
// 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;
  }
}

If anyone can please help me understand what I am missing here?如果有人可以请帮助我了解我在这里缺少什么?

the problem come from your reducers问题来自你的减速器

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

you have changed all state, it must be您已更改所有 state,它必须是

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM