React Native导航调用useTranslation报Invalid hook call错误
问题原因
Invalid hook call报错是因为违反了React Hook的基本调用规则:Hook只能在React函数组件、自定义Hook的顶层作用域内调用。你代码里把const { t, i18n } = useTranslation();写在了组件外的模块顶层全局位置,完全不符合调用要求,所以直接抛错。
另外你原来写的BottomTabBar组件还缺少tab选中态绑定、点击跳转的逻辑,就算解决了hook报错,点击tab也不会正常切换页面。
修复步骤
- 删除模块顶层(所有组件外部)错误的
useTranslation()调用代码 - 在需要用到翻译函数的
BottomTabBar组件内部顶层调用useTranslation,拿到t翻译方法 - 把
BottomNavigationTab上硬编码的title替换为t(你的翻译键)形式,同时补上tab选中和跳转逻辑
修正后的核心代码
修改StackNavigators.js如下:
import React, { useState, useEffect } from 'react'; import { createBottomTabNavigator } from '@react-navigation/bottom-tabs'; import { Keyboard } from 'react-native'; import TodayRates from '../pages/todayrates'; import Dashboard from '../pages/dashboard'; import UserService from '../services/userService'; import Profile from '../pages/profile'; import TodayActivities from '../pages/todayActivities'; import Tasks from '../pages/tasks'; import Task from '../pages/task'; import Settings from '../pages/settings'; import { BottomNavigation, BottomNavigationTab } from '@ui-kitten/components'; import { CreateTaskIcon } from '../assets/icons'; // For translation import '../../i18n/i18n'; import { useTranslation } from 'react-i18next'; // 移除此处原来错误的顶层useTranslation调用 const { Navigator, Screen } = createBottomTabNavigator(); // 把BottomTabBar从单表达式箭头函数改成带内部逻辑的函数组件 const BottomTabBar = ({ navigation, state }) => { // 符合Hook规则:在组件顶层调用useTranslation const { t } = useTranslation(); return ( <BottomNavigation selectedIndex={state.index} onSelect={index => navigation.navigate(state.routeNames[index])} > {/* 替换为你语言包中对应的实际key即可 */} <BottomNavigationTab title={t('dashboard')}/> <BottomNavigationTab title={t('activities')} /> <BottomNavigationTab icon={<CreateTaskIcon fill="#fff" width={30} height={30} />} /> <BottomNavigationTab title={t('tasks')} /> <BottomNavigationTab title={t('rates')} /> </BottomNavigation> ) }; const StackNavigators = () => { const [user, setUser] = useState({}); const [isKeyboardVisible, setIsKeyboardVisible] = useState(false); const getUser = async () => { await UserService.getCurrentUser().then((user) => { setUser(user); }) } useEffect(() => { getUser(); const showSubscription = Keyboard.addListener("keyboardDidShow", () => { setIsKeyboardVisible(true); }); const hideSubscription = Keyboard.addListener("keyboardDidHide", () => { setIsKeyboardVisible(false); }); return () => { showSubscription.remove(); hideSubscription.remove(); }; }, [isKeyboardVisible]); const getVisibilityStyle = (keyboardVisibility, props) => { if (!keyboardVisibility){ return <BottomTabBar {...props}/>; } return null; } return ( <Navigator initialRouteName="Dashboard" tabBar={ props => getVisibilityStyle(isKeyboardVisible, props) }> <Screen name="Dashboard" component={Dashboard} options={{ headerShown: false }} /> <Screen name="Activities" initialParams={{ user: user }} component={TodayActivities} options={{ headerShown: false }} /> <Screen name="+" component={Task} options={{ unmountOnBlur: true, headerShown: false }} /> <Screen name="Tasks" component={Tasks} options={{ unmountOnBlur: true, headerShown: false }} /> <Screen name="TodayRates" initialParams={{ user: user }} component={TodayRates} options={{ unmountOnBlur: true, headerShown: false }} /> <Screen name="Profile" component={Profile} options={{ headerShown: false }} /> <Screen name="Settings" component={Settings} options={{ headerShown: false }} /> <Screen name="EditTask" component={Task} options={{ unmountOnBlur: true, headerShown: false }} /> </Navigator> ); } export default StackNavigators;
注意事项
- 所有React Hook(包括useTranslation、useState、useEffect等)都不能在组件外的全局作用域、循环、条件分支、嵌套普通函数内调用,必须放在函数组件/自定义Hook的最顶层。
- 代码里t函数传入的键名,需要和你
en.json/es.json/no.json语言包里定义的键名完全对应,比如英文包里写"dashboard": "Dashboard"即可。 - 你其他页面翻译正常,说明i18n初始化配置没有问题,不需要修改
i18n.js的代码。
内容的提问来源于stack exchange,提问作者arild tarland
相关产品推荐
相关产品推荐

