RN中tabView组件点击tab无法切换View内容?

新手上路,请多包涵

ReactNative 中的tabview点击tab无法切换view,

import React, { useCallback, useEffect, useMemo, useState } from 'react';
import { View, StyleSheet, Dimensions, Text } from 'react-native';
import { TabView, SceneMap, TabBar } from 'react-native-tab-view';

type Route = {
    key: string;
    title: string;
};

type State = {
    index: number;
    routes: Route[];
};

const initialTabState: State = {
    index: 0,
    routes: [
        { key: 'tab1', title: 'Tab 1' },
        { key: 'tab2', title: 'Tab 2' },
        { key: 'tab3', title: 'Tab 3' },
        { key: 'tab4', title: 'Tab 4' },
        { key: 'tab5', title: 'Tab 5' },
        { key: 'tab6', title: 'Tab 6' },
        { key: 'tab7', title: 'Tab 7' },
        { key: 'tab8', title: 'Tab 8' },
    ],
};

const FirstRoute = () => (
    <View style={[styles.scene, { backgroundColor: '#ff4081' }]} />
);
const SecondRoute = () => (
    <View style={[styles.scene, { backgroundColor: '#673ab7' }]} />
);
const ThirdRoute = () => (
    <View style={[styles.scene, { backgroundColor: '#4caf50' }]} />
);
const FourthRoute = () => (
    <View style={[styles.scene, { backgroundColor: '#2196f3' }]} />
);
const FifthRoute = () => (
    <View style={[styles.scene, { backgroundColor: '#ffeb3b' }]} />
);
const SixthRoute = () => (
    <View style={[styles.scene, { backgroundColor: '#9c27b0' }]} />
);
const SeventhRoute = () => (
    <View style={[styles.scene, { backgroundColor: '#ffc107' }]} />
);
const EighthRoute = () => (
    <View style={[styles.scene, { backgroundColor: '#607d8b' }]} />
);



const TabScreen: React.FC = () => {
    const [tabState, setTabState] = useState<State>(initialTabState);

    const renderScene = SceneMap({
        '1': FirstRoute,
        '2': SecondRoute,
        '3': ThirdRoute,
        '4': FourthRoute,
        '5': FifthRoute,
        '6': SixthRoute,
        '7': SeventhRoute,
        '8': EighthRoute,
    });
    const renderTabBar = (props: any) => (
            <TabBar
                {...props}
                scrollEnabled
                tabStyle={styles.tabStyle}
                indicatorStyle={styles.indicatorStyle}
                style={styles.tabBarStyle}
                labelStyle={styles.labelStyle}
                onTabPress={({ route }) => {
                    console.log(route)
                    const index = initialTabState.routes.findIndex(item => item.key == route.key);
                    handleIndexChange(index);
                }}
        />
    );
    const handleIndexChange = (index: number) => {
        setTabState({ ...tabState, index });
    };
    useEffect(() => {
        console.log(tabState.index);
    }, [tabState])
    return (
        <View style={{ flex: 1}}>
            <TabView
                navigationState={tabState}
                renderScene={renderScene}
                onIndexChange={handleIndexChange}
                initialLayout={{ width: Dimensions.get('window').width }}
                renderTabBar={renderTabBar}
            />
        </View>
    );
};

const styles = StyleSheet.create({
    scene: {
        flex: 1,
    },
    tabStyle: {
        width: 'auto',
    },
    indicatorStyle: {
        backgroundColor: '#000',
    },
    tabBarStyle: {
        backgroundColor: '#fff',
    },
    labelStyle: {
        color: '#000',
    },
});

export default TabScreen;

"react": "18.2.0",
"react-native": "0.72.6",
"react-native-tab-view": "^3.5.1",

去除自定义tab改成原生的也不行

阅读 776
avatarAI BotBETA

从你提供的代码来看,TabScreen组件的逻辑基本上是正确的的。但是在 handleIndexChange 函数中,你使用的是 findIndex 函数,这可能会导致问题。因为 findIndex 函数返回的是找到的元素的索引,如果找不到则返回 -1。这样,当用户在 tab bar 中点击一个不存在的 tab 时,findIndex 将会返回 -1,然后你将这个值设置到 state 中,导致后续的渲染出现问题。

你可以修改 handleIndexChange 函数,确保只有当找到有效的 tab 时才更新 state。具体修改如下:

const handleIndexChange = (index: number) => {
    if (index >= 0 && index < initialTabState.routes.length) {
        setTabState({ ...tabState, index });
    }
};

以上修改可以确保只有当 index 在有效的范围内(0到routes.length-1)时,才会更新 state。这样,当用户点击一个不存在的 tab 时,就不会触发 state 的改变,也就不会出现你提到的问题了。

此外,我注意到你在 onTabPress 函数中打印了 route,但这个 route 的具体内容并未在你的代码中定义。如果你想获取当前 tab 的 key 或者 title,你可能需要修改一下这个函数,比如:

const renderTabBar = (props: any) => (
    <TabBar
    {...props}
    scrollEnabled
    tabStyle={styles.tabStyle}
    indicatorStyle={styles.indicatorStyle}
    style={styles.tabBarStyle}
    labelStyle={styles.labelStyle}
    onTabPress={({ route }) => {
        console.log(route.key);  // 打印当前 tab 的 key
        const index = initialTabState.routes.findIndex(item => item.key == route.key);
        handleIndexChange(index);
    }}
/>
);

这样你就可以在控制台看到当前被点击的 tab 的 key 了。希望这个答案能帮到你!如果你有更多的问题,欢迎继续提问。

1 个回答

SceneMap 里面的key 需要initialTabState 里面routes每一项的key对应,然后你👀掉onTabPress 就可以了

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题
宣传栏