React Navigation顶部Tab导航指示器样式指向错误修复问询
问题:Tab导航指示器始终指向上一个Tab而非当前选中项
我用React Navigation的createMaterialTopTabNavigator实现了Tab页面导航,导航逻辑和自定义tabBarLabel样式都正常,但tabBarIndicatorStyle始终应用在上一个Tab,不是当前选中的Tab,请问怎么修复?
代码示例
import AsyncStorage from '@react-native-async-storage/async-storage'; import {createMaterialTopTabNavigator} from '@react-navigation/material-top-tabs'; import {useIsFocused} from '@react-navigation/native'; import axios from 'axios'; import React, {useEffect, useState} from 'react'; import {ActivityIndicator, Text, View} from 'react-native'; import {Constants} from '../config/constants'; import {getAdvancedSearchAduanaService} from '../services/advancedSearch.service'; import Cards from './Cards'; import styles from './Style'; const CardList = ({route}) => { const {screenProps} = route.params; const [data, setData] = useState([]); const [action, setAction] = useState({}); const [config, setConfig] = useState([]); const [advancedSearch, setAdvancedSearch] = useState([]); const [collapseConfig, setCollapseConfig] = useState([]); const [pag, setPag] = useState(1); const [totalPag, setTotalPag] = useState(1); const [limit, setLimit] = useState(10); const [totalData, setTotalData] = useState(0); const [search, setSearch] = useState(''); const [loadData, setLoadData] = useState(false); const [clientsSelected, setClientsSelected] = useState('[]'); const [advancedObj, setAdvancedObj] = useState([]); const isFocused = useIsFocused(); useEffect(() => { if (isFocused) { console.log(`Tab ${route.name} está activo`); } }, [isFocused]); const setAdvanced = (advancedSearch) => { let obj = []; const newData = JSON.parse(JSON.stringify(advancedSearch)); newData.map((e) => { e.values.map((f) => { let objPush = { id: f.id, isDate: f.type === 'dateRange' ? true : false, value: f.type === 'dateRange' ? f.value && f.value2 ? { init: f.value, end: f.value2, } : '' : f.value ? f.value : '', }; obj.push(objPush); }); }); setAdvancedObj(obj); setPag(1); return obj; }; const initializeSearchedData = async () => { const dataSearched = await getAdvancedSearchAduanaService(); return dataSearched?.origin && dataSearched?.origin === route?.name ? setAdvanced(dataSearched.advancedSearch) : dataSearched?.advancedSearch; }; const getCatalogs = async () => { setLoadData(false); // const routeName = route.name; const selectedClients = await AsyncStorage.getItem('clientsSelected'); if (selectedClients) { try { setClientsSelected(selectedClients); await requestData(selectedClients); } catch (error) { console.log('error Integrada', error.response); setClientsSelected(selectedClients); await requestData(selectedClients); } finally { setLoadData(true); } } }; const requestData = async (res) => { const dataSearched = await initializeSearchedData(); const obj = { search, limit, pag, client: res, EsDTA: route.name === 'Impo' ? 0 : 1, advanced: dataSearched ?? advancedObj, }; let url = `${Constants.API_TRAZABILIDAD}customs/listCustomImports`; if (route.name === 'Expo') { url = `${Constants.API_TRAZABILIDAD}customs/listCustomExport`; } try { const response = await axios.post(url, obj); const newTotal = response.data.data[0] ? Number(response.data.data[0].Total) : 0; const newAllData = response.data.data.map((item) => ({ ...item, image: 2, })); setData(res === undefined ? [] : newAllData); setTotalData(newTotal); setTotalPag(Math.ceil(newTotal / limit)); } catch (error) { console.log('error Integrada', error.response); setData([]); setTotalData(0); setTotalPag(0); } }; const loadMore = async () => { let newPag = pag + 1; let obj = { search, limit, pag: newPag, client: clientsSelected, EsDTA: route === 'Impo' ? 0 : 1, advanced: advancedObj, }; setPag(newPag); await requestChange(obj); }; const requestChange = async (obj) => { let url = `${Constants.API_TRAZABILIDAD}customs/listCustomImports`; if (route.name === 'Expo') { url = `${Constants.API_TRAZABILIDAD}customs/listCustomExport`; } axios .post(url, obj) .then((response) => { let newAllData = data.concat(response.data.data); newAllData.map((e) => { e.image = 2; }); setData(newAllData); setLoadData(true); }) .catch((error) => { setData([]); setLoadData(true); console.log('error Integrada', error.response); }); }; useEffect(() => { const {action, config, collapseConfig, data} = screenProps; switch (route.name) { case 'Impo': setData(data); setAdvancedSearch(screenProps.advancedSearch); setAction(action); setConfig(config); setCollapseConfig(collapseConfig); break; case 'DTAs': setData(screenProps.dataDta); setAdvancedSearch(screenProps.advancedSearchDta); setAction(screenProps.actionDta); setConfig(screenProps.configDta); setCollapseConfig(screenProps.collapseConfigDta); break; default: setData(screenProps.dataExpo); setAdvancedSearch(screenProps.advancedSearchExpo); setAction(screenProps.actionExpo); setConfig(screenProps.configExpo); setCollapseConfig(screenProps.collapseConfigExpo); } getCatalogs(); }, []); return ( <View style={styles.bodyTabInternational}> {loadData ? ( <Cards data={data} config={config} collapseConfig={collapseConfig} action={action} navigation={screenProps.navigation} mapData={screenProps.mapData} mapCard={screenProps.mapCard} mapCardData={screenProps.mapCardData} charts={screenProps.charts} map={true} loadMore={() => loadMore()} advanced={true} graphs={true} advancedSearch={advancedSearch} routeName={route.name} route="Customs" setSearch={setSearch} /> ) : ( <View style={styles.containerLogin}> <ActivityIndicator size="large" color="#003F70" /> </View> )} </View> ); }; const Tab = createMaterialTopTabNavigator(); const MyApp = ({screenProps}) => { const isFocused = useIsFocused(); useEffect(() => { if (isFocused) { console.log(`Tab está activo`); } }, [isFocused]); return ( <Tab.Navigator screenOptions={({route}) => ({ tabBarLabel: () => { let title; if (route.name === 'Impo') title = 'Importaciones'; else if (route.name === 'DTAs') title = 'DTAs'; else title = 'Exportaciones'; return <Text style={styles.focusedStyleList}>{title}</Text>; }, tabBarIndicatorStyle: { backgroundColor: 'red', }, })}> <Tab.Screen name="Impo" component={CardList} initialParams={{screenProps}} /> <Tab.Screen name="DTAs" component={CardList} initialParams={{screenProps}} /> <Tab.Screen name="Expo" component={CardList} initialParams={{screenProps}} /> </Tab.Navigator> ); }; export default MyApp;
修复方案
1. 利用focused参数优化screenOptions
当前你的screenOptions只接收了route,没有利用focused状态判断Tab是否选中。修改screenOptions的参数,加入focused,同时确保指示器样式的逻辑正确:
<Tab.Navigator screenOptions={({ route, focused }) => ({ tabBarLabel: () => { let title; if (route.name === 'Impo') title = 'Importaciones'; else if (route.name === 'DTAs') title = 'DTAs'; else title = 'Exportaciones'; // 可选:根据focused动态切换label样式 return <Text style={focused ? styles.focusedStyleList : styles.unfocusedStyleList}>{title}</Text>; }, tabBarIndicatorStyle: { backgroundColor: 'red', // 若指示器宽度异常,可手动指定宽度适配Tab数量 width: '33.33%' }, })} >
2. 排查样式冲突
检查styles.bodyTabInternational或全局样式是否对Tab导航器的布局造成干扰,比如设置了padding、margin或position属性导致指示器偏移。可以暂时移除自定义样式,确认问题是否消失。
3. 升级React Navigation依赖
旧版本的@react-navigation/material-top-tabs可能存在指示器定位bug,执行以下命令升级到最新稳定版:
npm install @react-navigation/material-top-tabs@latest @react-navigation/native@latest
4. 优化组件重渲染逻辑
CardList组件中的空依赖useEffect调用getCatalogs可能导致初始化时的异常状态,确保useEffect的依赖项正确,避免不必要的状态更新影响Tab导航器的选中状态。
内容的提问来源于stack exchange,提问作者cosmos multi
相关产品推荐
相关产品推荐

