You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React Native抽屉导航仅生效一次,点击抽屉元素后应用冻结求助

React Native Drawer Navigation点击后应用冻结问题解决

问题描述

使用Drawer Navigation时,可从屏幕左侧滑动打开抽屉,但点击抽屉内元素后,整个应用冻结:滚动功能失效,抽屉无法再次打开,仅消息图标上的onPress方法仍能正常工作。

相关代码

App.js

const App = () => {
  return (
    <NavigationContainer>
      <MainNavigation />
    </NavigationContainer>
  );
};
const Stack = createStackNavigator();
const Drawer = createDrawerNavigator();

const MainMenuNavigation = () => {
  return (
    <Drawer.Navigator screenOptions={{"header": () => null}}>
      <Drawer.Screen name={Routes.Home} component={Home} />
      <Drawer.Screen name={Routes.Profile} component={Profile} />
    </Drawer.Navigator>
  );
};

const mainNavigation = () => {
  return (
    <Stack.Navigator
      initialRouteName={Routes.Home}
      screenOptions={{"header": () => null, "headerShown": false}}>
      <Stack.Screen name={'Drawer'} component={MainMenuNavigation} />
    </Stack.Navigator>
  );
};

Home页面代码

import React, {useState} from 'react';
import {
  SafeAreaView,
  Text,
  View,
  Pressable,
  FlatList,
  StatusBar,
} from 'react-native';
import Title from '../../components/title/Title';
import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome';
import {faEnvelope} from '@fortawesome/free-regular-svg-icons';
import style from './style';
import globalStyle from '../../Zassets/styles/main';
import UserStory from '../../components/UserStory/UserStory';
import UserPost from '../../components/userPosts/userPost';
import { Routes } from '../../navigation/routes';

const Home = ({navigation}) => {
  const data = [
    {firstName: 'joseph', id: 1},
    {firstName: 'Angel', id: 2},
    {firstName: 'White', id: 3},
    {firstName: 'Olivier', id: 4},
    {firstName: 'john', id: 5},
    {firstName: 'nick', id: 6},
    {firstName: 'black', id: 7},
    {firstName: 'Ann', id: 8},
    {firstName: 'Mary', id: 9},
  ];
  const pageSize = 4;
  const [pageNumber, setPageNumer] = useState(1);
  const [loading, setLoading] = useState(false);
  const [renderedData, setRenderedData] = useState(data.slice(0, pageSize));

  const posts = [
    {
      firstName: 'Allison',
      lastName: 'becker',
      location: 'Sukabumi, Jawa Barat',
      likes: 1200,
      comments: 24,
      bookmarks: 55,
      id: 1,
    },
    {
      firstName: 'Jennifer',
      lastName: 'Wilkson',
      location: 'Pondok leugnsir, Jawa Barat',
      likes: 1527,
      comments: 15,
      bookmarks: 25,
      id: 2,
    },
    {
      firstName: 'Adam',
      lastName: 'spera',
      location: 'Boston, Massachusetts',
      likes: 125,
      comments: 6,
      bookmarks: 18,
      id: 3,
    },
    {
      firstName: 'john',
      lastName: 'doe',
      location: 'NY, US',
      likes: 1525,
      comments: 63,
      bookmarks: 73,
      id: 4,
    },
    {
      firstName: 'mary',
      lastName: 'Ann',
      location: 'Paris, France',
      likes: 244,
      comments: 23,
      bookmarks: 13,
      id: 5,
    },
  ];
  const postsPageSize = 2;
  const [pageNumberPosts, setpageNumberPosts] = useState(1);
  const [loadingPosts, setloadingPosts] = useState(false);
  const [renderedDataPosts, setrenderedDataPosts] = useState(
    posts.slice(0, postsPageSize),
  );

  const pagination = (data, pageNumber, pageSize, posts = false) => {
    let startIndex = (pageNumber - 1) * pageSize;
    if (startIndex > data.length) {
      return [];
    }

    if (!posts) {
      setPageNumer(pageNumber);
    } else {
      setpageNumberPosts(pageNumber);
    }
    return data.slice(startIndex, startIndex + pageSize);
  };
  
  return (
    <SafeAreaView style={globalStyle.backgroundWhite}>
      <StatusBar backgroundColor={'#fff'} barStyle={'dark-content'} />
      <FlatList
        ListHeaderComponent={
          <>
            <View style={style.header}>
              <Title title={"Let's Explore"} />
              <Pressable
                onPress={() => {
                  navigation.navigate(Routes.Profile);
                }}
                style={style.messageIcon}>
                <FontAwesomeIcon
                  icon={faEnvelope}
                  color={'#CACDDE'}
                  size={20}
                />
                <View style={style.messageIconView}>
                  <Text style={style.messageIconText}>2</Text>
                </View>
              </Pressable>
            </View>
            <View style={style.userStoryContainer}>
              <FlatList
                onMomentumScrollBegin={() => setLoading(false)}
                onEndReachedThreshold={0.5}
                keyExtractor={item => item.id.toString()}
                onEndReached={() => {
                  if (!loading) {
                    setLoading(true);
                    setRenderedData(prev => [
                      ...prev,
                      ...pagination(data, pageNumber + 1, pageSize),
                    ]);
                    setLoading(false);
                  }
                }}
                showsHorizontalScrollIndicator={false}
                horizontal={true}
                data={renderedData}
                renderItem={({item}) => (
                  <UserStory firstName={item.firstName} />
                )}
              />
            </View>
          </>
        }
        onMomentumScrollBegin={() => setloadingPosts(false)}
        onEndReachedThreshold={0.5}
        keyExtractor={item => item.id.toString() + ' post'}
        onEndReached={() => {
          if (!loadingPosts) {
            setloadingPosts(true);
            setrenderedDataPosts(prev => [
              ...prev,
              ...pagination(posts, pageNumberPosts + 1, postsPageSize, true),
            ]);
            setloadingPosts(false);
          }
        }}
        showsVerticalScrollIndicator={false}
        data={renderedDataPosts}
        renderItem={({item}) => (
          <View style={style.userPostContainer}>
            <UserPost
              firstName={item.firstName}
              lastName={item.lastName}
              comments={item.comments}
              likes={item.likes}
              bookmarks={item.bookmarks}
              location={item.location}
            />
          </View>
        )}
      />
    </SafeAreaView>
  );
};

export default Home;

解决方案

1. 修正导航结构的错误配置

当前Stack导航的initialRouteName设置为Routes.Home,但Stack中仅包含名为Drawer的screen,这会导致导航状态混乱。同时,不必要的Stack嵌套会增加导航复杂度,建议直接使用Drawer作为主导航:

// 修改后的Navigation代码
const Drawer = createDrawerNavigator();

const MainNavigation = () => {
  return (
    <Drawer.Navigator screenOptions={{header: () => null}}>
      <Drawer.Screen name={Routes.Home} component={Home} />
      <Drawer.Screen name={Routes.Profile} component={Profile} />
    </Drawer.Navigator>
  );
};

如果必须保留Stack嵌套,需修正initialRouteName为Stack中存在的screen名称:

const Stack = createStackNavigator();
const Drawer = createDrawerNavigator();

const MainMenuNavigation = () => {
  return (
    <Drawer.Navigator screenOptions={{header: () => null}}>
      <Drawer.Screen name={Routes.Home} component={Home} />
      <Drawer.Screen name={Routes.Profile} component={Profile} />
    </Drawer.Navigator>
  );
};

const MainNavigation = () => {
  return (
    <Stack.Navigator
      initialRouteName={'Drawer'} // 改为Stack中存在的screen名称
      screenOptions={{header: () => null, headerShown: false}}>
      <Stack.Screen name={'Drawer'} component={MainMenuNavigation} />
    </Stack.Navigator>
  );
};

2. 修复FlatList分页逻辑的状态更新问题

原pagination函数中直接修改页码状态,且onEndReached回调同步执行状态更新,会导致频繁的状态变更引发UI阻塞。调整逻辑,让分页函数仅负责数据切片,状态更新在回调中处理:

// 重写pagination函数,仅返回分页数据
const pagination = (data, pageNumber, pageSize) => {
  const startIndex = (pageNumber - 1) * pageSize;
  if (startIndex >= data.length) {
    return [];
  }
  return data.slice(startIndex, startIndex + pageSize);
};

// 修改故事FlatList的onEndReached回调
onEndReached={() => {
  if (!loading) {
    setLoading(true);
    const nextPage = pageNumber + 1;
    const newData = pagination(data, nextPage, pageSize);
    if (newData.length > 0) {
      setRenderedData(prev => [...prev, ...newData]);
      setPageNumer(nextPage);
    }
    setLoading(false);
  }
}}

// 修改帖子FlatList的onEndReached回调
onEndReached={() => {
  if (!loadingPosts) {
    setloadingPosts(true);
    const nextPage = pageNumberPosts + 1;
    const newData = pagination(posts, nextPage, postsPageSize);
    if (newData.length > 0) {
      setrenderedDataPosts(prev => [...prev, ...newData]);
      setpageNumberPosts(nextPage);
    }
    setloadingPosts(false);
  }
}}

3. 检查Profile页面的组件实现

应用冻结可能也与Profile页面的代码有关,需确保:

  • 没有无限循环的状态更新
  • 未在渲染阶段执行耗时操作
  • 正确使用滚动组件(如FlatList或ScrollView),避免布局溢出导致UI阻塞

4. 确保导航库版本兼容

更新@react-navigation相关依赖到最新稳定版,避免版本不兼容导致的异常:

npm install @react-navigation/native@latest @react-navigation/drawer@latest react-native-gesture-handler@latest react-native-reanimated@latest

内容的提问来源于stack exchange,提问作者legates

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.19 14:54:57