【问题标题】:react native navigate to another stack with params使用参数反应本机导航到另一个堆栈
【发布时间】:2020-09-05 03:17:09
【问题描述】:
import React from 'react';
import { createBottomTabNavigator } from '@react-navigation/bottom-tabs';
import { enableScreens } from 'react-native-screens';
import { createNativeStackNavigator } from 'react-native-screens/native-stack';


enableScreens();
const Tab = createBottomTabNavigator();
const RootStack = createNativeStackNavigator();
const WardrobeStack = createNativeStackNavigator();
const OutfitStack = createNativeStackNavigator();
const CreateLookStack = createNativeStackNavigator();
const ProfileStack = createNativeStackNavigator();


export const WardrobeNavigator = () => {
    return (
        <WardrobeStack.Navigator
            screenOptions={{
                headerShown: false
            }}
            initialRouteName='Wardrobe'>
            <WardrobeStack.Screen name="Wardrobe" component={Wardrobe} /> // <== navigate to here with params
            <WardrobeStack.Screen name="Profile" component={Profile} />
            <WardrobeStack.Screen name="AddFirstItem" component={AddFirstItem} />
            <WardrobeStack.Screen name="RetakeContinue" component={RetakeContinue} />
            <WardrobeStack.Screen name="CategoryBrand" component={CategoryBrand} />
            <WardrobeStack.Screen name="DeleteCategory" component={DeleteCategory} />
        </WardrobeStack.Navigator>
    );
}

export const OutfitNavigator = () => {
    return (
        <OutfitStack.Navigator
            screenOptions={{
                headerShown: false
            }}
            initialRouteName='LookBook'>
            <OutfitStack.Screen name="Outfits" component={Outfits} />
            <OutfitStack.Screen name="LookBook" component={LookBook} />
            <OutfitStack.Screen name="LookBookList" component={LookBookList} /> // <== navigate from here
            <OutfitStack.Screen name="Profile" component={Profile} />
            <OutfitStack.Screen name="ShoppingList" component={ShoppingList} />
        </OutfitStack.Navigator>
    );
}

export const CreateLookNavigator = () => {
return (
  <CreateLookStack.Navigator
    screenOptions={{
      headerShown: false,
    }}
    initialRouteName="NewLook">
    <CreateLookStack.Screen name="NewLook">
        {props => (
        <NewLook
            {...props}
            initialParams={{
                lookSaveType: AppConstants.DEFAULT_LOOK_SAVE_TYPE,
            }}
        />
        )}
    </CreateLookStack.Screen>
    <CreateLookStack.Screen name="SaveLook" component={SaveLook} />
  </CreateLookStack.Navigator>
  );
}

export const ProfileNavigator = () => {
    return (
        <ProfileStack.Navigator
            screenOptions={{
                headerShown: false
            }}
            initialRouteName='ProfileOnbarding'>
            <ProfileStack.Screen name="ProfileOnbarding" component={ProfileOnboarding} />
            <ProfileStack.Screen name="ProfileAllSet" component={ProfileAllSet} />
        </ProfileStack.Navigator>
    );
}

export const RootNavigator = () => {
    return (
        <RootStack.Navigator
            screenOptions={{
                headerShown: false
            }}
            initialRouteName='Main'
            mode='modal'>
            <RootStack.Screen name="Main" component={BottomTabNavigator} />
            <RootStack.Screen name="Brands" component={BrandStores} />
            <RootStack.Screen name="ItemScreen" component={ItemScreen} />
            <RootStack.Screen name="CreateLook" component={CreateLookNavigator} />
            <RootStack.Screen name="ShoppingList" component={ShoppingList} />
            <RootStack.Screen name="ProfileOnboarding" component={ProfileNavigator} />
            {/* add full screen appear as modal */}
        </RootStack.Navigator>
    );
}

export const BottomTabNavigator = () => {
    return (

        <Tab.Navigator
            initialRouteName="Outfits"
            screenOptions={({ route }) => ({
                tabBarIcon: ({ focused, color, size }) => {
                    switch (route.name) {
                        case 'Explore':
                            return focused ? <ActiveTeleIcon /> : <InactiveTeleIcon />
                        case 'Bookings':
                            return focused ? <ActiveBookingIcon /> : <InactiveBookingIcon />
                        case 'Wardrobe':
                            return focused ? <ActiveWardrobeIcon /> : <InactiveWardrobeIcon />
                        case 'Outfits':
                            return focused ? <ActiveOutfitsIcon /> : <InactiveOutfitsIcon />
                        case 'Chat':
                            return focused ? <ActiveChatIcon /> : <InactiveChatIcon />
                    }
                },
            })}
            tabBarOptions={{
                activeTintColor: Colors.PRIMARY,
                inactiveTintColor: Colors.SECONDARY_TEXT,
                statusBarStyle: 'light-content',
                style: styles.tabContainer,
                labelStyle: styles.labelStyle,
                allowFontScaling: true,
            }}
        >
            <Tab.Screen
                name="Explore"
                component={Explore}
                options={{
                    tabBarLabel: 'Explore'
                }}
            />
            <Tab.Screen
                name="Bookings"
                component={Bookings}
                options={{
                    tabBarLabel: 'Bookings',
                }}
            />
            <Tab.Screen
                name="Wardrobe"
                component={WardrobeNavigator}
                options={{
                    tabBarLabel: 'Wardrobe',
                }}
            />
            <Tab.Screen
                name="Outfits"
                component={OutfitNavigator}
                options={{
                    tabBarLabel: 'Outfits',
                }}
            />
            <Tab.Screen
                name="Chat"
                component={Chat}
                options={{
                    tabBarLabel: 'Chat',
                }}
            />
        </Tab.Navigator>
    );
};

我想从 LookBookList 导航到 Wardrobe,这就是我在 lookbook-list.js 文件中所做的。

  <HeaderBar
    backButton
    leftClick={() => navigation.goBack()}
    rightIcon={<HangerIcon />}
    rightIconClick={() => {
      navigation.navigate('Wardrobe', {openModal: true});
    }}
  />

我的 Wardrobe.js 文件:

export const Wardrobe = ({route}) => {
    console.log('route.params', route.params) // <== this is undefined ???
    const {openModal} = route.params;

    const navigation = useNavigation();
    const [isVisible, setIsVisible] = useState(openModal);

我收到以下错误:

TypeError: undefined is not an object (evaluating 'route.params.openModal')

【问题讨论】:

    标签: react-native react-navigation


    【解决方案1】:

    通过查看您的代码,我认为问题在于您还可以从标签访问WardrobeNavigator,而不仅仅是导航。由于您的初始屏幕是WardrobeNavigator 中的Wardrobe,并且由于您没有传递initialParams,因此在导航设置参数之前评估route.params.openModal

    为了防止它未定义并提供默认值,我们可以访问以下语法:

    const openModal = route.params?.openModal ?? false; // So false is the default value here
    

    https://reactnavigation.org/docs/upgrading-from-4.x/#no-more-getparam

    更新

    它不起作用的原因是因为您正在更新 WardrobeNavigator 而不是 Wardrobe 的参数。由于您想将参数传递给嵌套屏幕,您可以执行以下操作:

    navigation.navigate('Wardrobe', {
      screen: 'Wardrobe',
      params: { openModal: true },
    })
    

    【讨论】:

    • 我试过initialParams,我现在可以看到 route.params.openModal 但是当我使用navigation.navigate('Wardrobe', {openModal: true}) 从 LookbookList 组件导航时,屏幕会改变但值没有改变,它仍然是false ;
    • 谢谢这个工作,但我的模式没有打开,因为 openModal 作为初始状态传递给 setState 所以我不得不在 useEffect 中再次 setState 传递 openModal 参数。然后下一个问题是关于进一步导航的路线参数没有清除或重置,这再次需要 useEffect 这样做。我已经求助于 react 的 Context api 来处理它。我会用我的实现来回答更多细节。非常感谢您的帮助。
    【解决方案2】:

    所以我已经使用 React 的 Context API 解决了这个问题。

    wardrobe-context.js 中创建了一个上下文:

    import React, {useState} from 'react';
    
    export const WardrobeContext = React.createContext();
    
    function WardrobeProvider(props) {
      const [isAddItemModalOpen, setIsAddItemModalOpen] = useState(false);
    
      return (
        <WardrobeContext.Provider
          value={{isAddItemModalOpen, setIsAddItemModalOpen}}>
          {props.children}
        </WardrobeContext.Provider>
      );
    }
    
    export default WardrobeProvider;
    

    navigation.js 文件中,用WardrobeProvider 包装了我的根导航堆栈:

    export const RootNavigator = () => {
        return (
            <WardrobeProvider> // <== wrapper context provider
                <RootStack.Navigator
                    screenOptions={{
                        headerShown: false
                    }}
                    initialRouteName='Main'
                    mode='modal'>
                    <RootStack.Screen name="Main" component={BottomTabNavigator} />
                    <RootStack.Screen name="Brands" component={BrandStores} />
                    <RootStack.Screen name="ItemScreen" component={ItemScreen} />
                    <RootStack.Screen name="CreateLook" component={CreateLookNavigator} />
                    <RootStack.Screen name="ShoppingList" component={ShoppingList} />
                    <RootStack.Screen name="StylistInstructions" component={ProfileNavigator} />
                    {/* add full screen appear as modal */}
                </RootStack.Navigator>
            </WardrobeProvider>
        );
    }
    

    最后,在 Wardrobe.js 中:

    import React, { useState, useEffect, useContext } from 'react';
    import { useFocusEffect } from '@react-navigation/native';
    import { WardrobeContext } from '../../../context/wardrobe-context';
    export const Wardrobe = () => {
        const {isAddItemModalOpen, setIsAddItemModalOpen} = useContext(WardrobeContext);
    
        const [isVisible, setIsVisible] = useState(false);
    
        useFocusEffect(
            React.useCallback(() => {
                setIsVisible(isAddItemModalOpen) // <== set value here to open modal
              return () => setIsAddItemModalOpen(false); // <== clear/reset the value on navigation change
            }, [isAddItemModalOpen])
        );
    

    useFocusEffect 用于设置isVisibleisVisible 的值Wardrobe.js 屏幕聚焦时的状态,屏幕未聚焦时上下文中的值设置为false用户导航到另一个屏幕。

    lookbook-list.js 导航到 Wardrobe.js 更新上下文值:

      import {WardrobeContext} from '../../../context/wardrobe-context';
    
      <HeaderBar
        backButton
        leftClick={() => navigation.goBack()}
        rightIcon={<HangerIcon />}
        rightClick={() => {
          wardrobeContext.setIsAddItemModalOpen(true); // <== update context here
          navigation.navigate('Wardrobe'); // <== and then navigate
        }}
      />
    

    欢迎提出改进建议。谢谢

    【讨论】:

      猜你喜欢
      • 2022-10-16
      • 2019-10-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-01-25
      • 2013-07-23
      • 1970-01-01
      • 2023-01-27
      相关资源
      最近更新 更多