【问题标题】:React navigation 5: Undefined is not an objectReact Navigation 5:未定义不是对象
【发布时间】:2020-08-12 05:13:35
【问题描述】:

在我的 UserProductsScreen.js 文件中,我传递了一个参数 id,以便我可以在导航中选择它:

const UserProductsScreen = props => {
    const userProducts = useSelector(state => state.products.userProducts);
    
    // Navigate to EditProduct
    const editProductHandler = (id) => {
        props.navigation.navigate('EditProduct', { productId: id })
    };  

然后,在我的navigator.js 文件中,我尝试检查它是否存在,以便我可以决定哪个标题标题显示“添加产品”或“编辑产品”:

  <AdminNavigator.Screen
                name="EditProduct"
                component={EditProductScreen}
                options={({ route }) => {
                    const productId = route.params.productId;
                    return {
                        title: productId ? "Edit Product" : "Add Product"
                    };
                }}
            />

如果它收到 productId 并且确实收到了,我对此进行了测试,但是当点击加号图标时我收到此错误:TypeError: undefined is not an object (evaluating 'route.params.productId')

我不确定它的含义,但我只是检查它是否存在,以便我可以动态更改标题。

为了记录,这是我完整的navigation

import React from 'react';
import { NavigationContainer } from '@react-navigation/native';
import { createStackNavigator } from '@react-navigation/stack';
import { createDrawerNavigator } from '@react-navigation/drawer';
import { Platform } from 'react-native';

import { Ionicons } from '@expo/vector-icons';

import ProductsOverviewScreen from '../screens/shop/ProductsOverviewScreen';
import ProductDetailScreen from '../screens/shop/ProductDetailScreen';
import CartScreen from '../screens/shop/CartScreen';
import OrdersScreen from '../screens/shop/OrdersScreen';
import UserProductsScreen from '../screens/user/UserProductsScreen';
import EditProductScreen from '../screens/user/EditProductScreen';

import Colors from '../constants/Colors';
import { HeaderButtons, Item } from 'react-navigation-header-buttons';
import HeaderButton from '../components/UI/HeaderButton';

const ProductsNavigator = createStackNavigator();

const ProductsNavMenu = () => {
    return (
        <ProductsNavigator.Navigator
            screenOptions={{
                headerStyle: {
                    backgroundColor: Platform.OS === 'android' ? Colors.primary : ''
                },
                headerTintColor: Platform.OS === 'android' ? 'white' : Colors.primary,
                headerTitleStyle: {
                    fontSize: 17,
                    fontFamily: 'poppins-bold'
                },
                headerBackTitleStyle: {
                    fontFamily: 'poppins-regular'
                }
            }}>
            <ProductsNavigator.Screen
                name="Products"
                component={ProductsOverviewScreen}
                options={({ navigation }) => {
                    return {
                        headerRight: () => (
                            <HeaderButtons HeaderButtonComponent={HeaderButton}>
                                <Item
                                    title="Cart"
                                    iconName={Platform.OS === 'android' ? 'md-cart' : 'ios-cart'}
                                    onPress={() => navigation.navigate('Cart')}
                                />
                            </HeaderButtons>
                        ),
                        headerLeft: () => (
                            <HeaderButtons HeaderButtonComponent={HeaderButton}>
                                <Item
                                    title='Menu'
                                    iconName={Platform.OS === 'android' ? 'md-menu' : 'ios-menu'}
                                    onPress={() => {
                                        navigation.toggleDrawer();
                                    }}
                                />
                            </HeaderButtons>
                        )
                    };
                }}
            />
            <ProductsNavigator.Screen
                name="ProductDetail"
                component={ProductDetailScreen}
                options={({ route }) => {
                    const productTitle = route.params.productTitle;
                    return {
                        title: productTitle
                    };
                }}
            />
            <ProductsNavigator.Screen
                name="Cart"
                component={CartScreen}
            />
        </ProductsNavigator.Navigator>
    );
};


// Create a separate stack navigation 
// for orders 
const OrdersNavigator = createStackNavigator();

const OrdersNavMenu = () => {
    return (
        <OrdersNavigator.Navigator
            mode="modal"
            screenOptions={{
                headerStyle: {
                    backgroundColor: Platform.OS === 'android' ? Colors.primary : ''
                },
                headerTintColor: Platform.OS === 'android' ? 'white' : Colors.primary,
                headerTitleStyle: {
                    fontSize: 17,
                    fontFamily: 'poppins-bold'
                },
                headerBackTitleStyle: {
                    fontFamily: 'poppins-regular'
                }
            }}
        >
            <OrdersNavigator.Screen
                name="Orders"
                component={OrdersScreen}
                options={({ navigation }) => {
                    return {
                        headerLeft: () => (
                            <HeaderButtons HeaderButtonComponent={HeaderButton}>
                                <Item
                                    title='Menu'
                                    iconName={Platform.OS === 'android' ? 'md-menu' : 'ios-menu'}
                                    onPress={() => {
                                        navigation.toggleDrawer();
                                    }}
                                />
                            </HeaderButtons>
                        )
                    };
                }}

            />
        </OrdersNavigator.Navigator>
    );
};





// Create a separate stack navigation 
// for userProductsScreen
const AdminNavigator = createStackNavigator();

const AdminNavMenu = () => {
    return (
        <AdminNavigator.Navigator
            mode="modal"
            screenOptions={{
                headerStyle: {
                    backgroundColor: Platform.OS === 'android' ? Colors.primary : ''
                },
                headerTintColor: Platform.OS === 'android' ? 'white' : Colors.primary,
                headerTitleStyle: {
                    fontSize: 17,
                    fontFamily: 'poppins-bold'
                },
                headerBackTitleStyle: {
                    fontFamily: 'poppins-regular'
                }
            }}
        >
            <AdminNavigator.Screen
                name="UserProducts"
                component={UserProductsScreen}
                options={({ navigation }) => {
                    return {
                        title: "User Products",
                        headerLeft: () => (
                            <HeaderButtons HeaderButtonComponent={HeaderButton}>
                                <Item
                                    title='User Products'
                                    iconName={Platform.OS === 'android' ? 'md-list' : 'ios-list'}
                                    onPress={() => {
                                        navigation.toggleDrawer();
                                    }}
                                />
                            </HeaderButtons>
                        ),
                        headerRight: () => (
                            <HeaderButtons HeaderButtonComponent={HeaderButton}>
                                <Item
                                    title='Add'
                                    iconName={Platform.OS === 'android' ? 'md-create' : 'ios-create'}
                                    onPress={() => {
                                        navigation.navigate('EditProduct');
                                    }}
                                />
                            </HeaderButtons>
                        )
                    };
                }}

            />

            <AdminNavigator.Screen
                name="EditProduct"
                component={EditProductScreen}
                options={({ route }) => {
                    const productId = route.params.productId;
                    return {
                        title: productId ? "Edit Product" : "Add Product"
                    };
                }}
            />
        </AdminNavigator.Navigator>
    );
};







const ShopNavigator = createDrawerNavigator();

const ShopNavMenu = () => {
    return (
        <NavigationContainer>
            <ShopNavigator.Navigator>
                <ShopNavigator.Screen
                    name="Products"
                    component={ProductsNavMenu}
                    options={{
                        drawerIcon: ({ focused, size }) => (
                            <Ionicons
                                name={Platform.OS === 'android' ? 'md-cart' : 'ios-cart'}
                                size={23}
                                color={focused ? '#7cc' : '#ccc'}
                            />
                        )
                    }}
                />
                <ShopNavigator.Screen
                    name="Orders"
                    component={OrdersNavMenu}
                    options={{
                        drawerIcon: ({ focused, size }) => (
                            <Ionicons
                                name={Platform.OS === 'android' ? 'md-list' : 'ios-list'}
                                size={23}
                                color={focused ? '#7cc' : '#ccc'}
                            />
                        )
                    }}
                />
                <ShopNavigator.Screen
                    name="Admin"
                    component={AdminNavMenu}
                    options={{
                        drawerIcon: ({ focused, size }) => (
                            <Ionicons
                                name={Platform.OS === 'android' ? 'md-create' : 'ios-create'}
                                size={23}
                                color={focused ? '#7cc' : '#ccc'}
                            />
                        )
                    }}
                />
            </ShopNavigator.Navigator>
        </NavigationContainer>
    );
};

export default ShopNavMenu;

更新:所以我尝试在魔法发生的UserProductsScreen 上使用setParams。我使用 useEffect 将初始 productId 设置为空白:

import React, { useEffect } from 'react';
import { CommonActions } from '@react-navigation/native';

const UserProductsScreen = props => {
    const userProducts = useSelector(state => state.products.userProducts);
    
    // Navigate to EditProduct
    const editProductHandler = (id) => {
        props.navigation.navigate('EditProduct', { productId: id })
    };  

        // Set initial productId params not until the editProductHandler is triggerred
        useEffect(() => {
            props.navigation.dispatch(CommonActions.setParams({ productId: '' }));
        }, []); 
    

    // dispatch
    const dispatch = useDispatch();

然后在我的navigation 上,我尝试通过我的 headerRight 捕获 productId:

    <AdminNavigator.Screen
    name="UserProducts"
    component={UserProductsScreen}
    options={({ navigation, route }) => {
        const productId = route.params.productId;
        return {
            title: "User Products",
            headerLeft: () => (
                <HeaderButtons HeaderButtonComponent={HeaderButton}>
                    <Item
                        title='User Products'
                        iconName={Platform.OS === 'android' ? 'md-list' : 'ios-list'}
                        onPress={() => {
                            navigation.toggleDrawer();
                        }}
                    />
                </HeaderButtons>
            ),
            headerRight: () => (
                <HeaderButtons HeaderButtonComponent={HeaderButton}>
                    <Item
                        title='Add'
                        iconName={Platform.OS === 'android' ? 'md-create' : 'ios-create'}
                        onPress={() => {
                            navigation.navigate('EditProduct');
                        }}
                    />
                </HeaderButtons>
            )
        };
    }}

/>

但这也会影响常规导航中的 id。现在点击编辑按钮时也会显示上面的错误。

【问题讨论】:

  • 您可以推送您的代码并在此处留下链接吗?

标签: javascript reactjs react-native react-navigation


【解决方案1】:

问题来了

     <HeaderButtons HeaderButtonComponent={HeaderButton}>
                        <Item
                            title='Add'
                            iconName={Platform.OS === 'android' ? 'md-create' : 'ios-create'}
                            onPress={() => {
                                navigation.navigate('EditProduct');
                            }}
                        />
                    </HeaderButtons>

当您从标题右键导航时,您没有传递任何参数。

如果此时您无法访问路由参数,则必须在导航到页面后使用 setParams 设置参数。 你可以参考文档 https://reactnavigation.org/docs/navigation-prop#setparams

更新: 因此,当您在不传递任何内容的情况下导航时, route.params 是未定义的 当您访问未定义的属性时,它会引发错误

验证这一点的方法是使用下面的可选链接

const productId = route.params?.productId;

这将仅在参数可用时设置值。

【讨论】:

  • 我可以像这样将 headerRight 中的 setParams 设置为 false 或空白以避免错误吗?
  • 那么在navigation.navigate('EditProduct'); 之后我会加上setParams({ productId: '' }) 或`setParams({ productId: false })` 这可能吗?
  • 不不,您必须在屏幕级别执行此操作,可能在 useEffect 或 useFocusEffect 中
  • 我尝试使用 useEffect 为 productId 设置初始参数,但在单击编辑时会覆盖导航参数。
  • 一如既往,你是个天才!
【解决方案2】:

我在第一个屏幕加载时遇到了这个问题。 参数未定义,我通过使用initialParams 选项为我的第一个屏幕设置参数来修复它。

<Stack.Screen
  component={LCWebView}
  options={{
    title: 'Awesome app',
    myopt: 'test',
  }}
  initialParams={{ url: url_goes_here }}
/>

【讨论】:

    猜你喜欢
    • 2020-06-25
    • 1970-01-01
    • 1970-01-01
    • 2019-05-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多