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)
};
我正在构建一个 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)
};