React 导航 5:Undefined 不是对象
在我的
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 不是对象(评估'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。现在,单击编辑按钮时也会显示上述错误。
问题就在这里
<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;
仅当 params 可用时,这才会设置值。
我在第一个屏幕加载时遇到了这个问题。
参数未定义
,我通过使用
initialParams
选项为第一个屏幕设置参数来修复此问题。
<Stack.Screen
component={LCWebView}
options={{
title: 'Awesome app',
myopt: 'test',
}}
initialParams={{ url: url_goes_here }}
/>