React Native中组件已用Provider包裹仍遇Redux上下文缺失错误
React Native Redux Toolkit 会话管理报错解决
问题描述
我是React Native新手,尝试用Redux Toolkit实现会话管理,代码遵循官方文档编写,且已用<Provider>包裹组件,但仍报错:
could not find react redux context value please ensure the component is wrapped in
尝试了网上各种方法都无法解决,相关代码如下:
AppNavigation.tsx
import React from 'react'; import {NavigationContainer} from '@react-navigation/native'; import {createNativeStackNavigator} from '@react-navigation/native-stack'; import Signup from '../Screens/Signup'; import NewSignIn from '../Screens/NewSignIn'; import FullfillmentScreen from '../../FullfillmentScreen'; import Combined from '../Screens/Combined'; import Oragnization from '../Screens/Oragnization'; import {useDispatch, useSelector} from 'react-redux/es/exports'; import {onAuthStateChanged} from 'firebase/auth'; import {auth} from '../../firebase/firebase.config'; import {setUser} from '../redux/slices/user'; const Stack = createNativeStackNavigator(); const AppNavigation = () => { const {user} = useSelector(state => state.user); const dispatch = useDispatch(); onAuthStateChanged(auth, u => { console.log('GOT USER====>', u); dispatch(setUser(u)); //setting user in redux store }); if (user) { return ( <NavigationContainer> <Stack.Navigator screenOptions={{headerShown: false}}> {/* <Stack.Screen name="NewSignIn" component={NewSignIn} /> */} <Stack.Screen name="Organization" component={Oragnization} /> <Stack.Screen name="Combined" component={Combined} /> <Stack.Screen name="FullfillmentScreen" component={FullfillmentScreen} /> </Stack.Navigator> </NavigationContainer> ); } else { return ( <NavigationContainer> <Stack.Navigator screenOptions={{headerShown: false}}> <Stack.Screen name="NewSignIn" component={NewSignIn} /> <Stack.Screen name="Signup" component={Signup} /> {/* <Stack.Screen name="Organization" component={Oragnization} /> <Stack.Screen name="Combined" component={Combined} /> <Stack.Screen name="FullfillmentScreen" component={FullfillmentScreen} /> */} </Stack.Navigator> </NavigationContainer> ); } }; export default AppNavigation;
App.tsx
/** * Sample React Native App * https://github.com/facebook/react-native * * @format */ import React, {useState, useEffect} from 'react'; import type {PropsWithChildren} from 'react'; import { SafeAreaView, ScrollView, StatusBar, StyleSheet, Text, useColorScheme, View, } from 'react-native'; import {NavigationContainer} from '@react-navigation/native'; import {createNativeStackNavigator} from '@react-navigation/native-stack'; import Signin from './src/Screens/Signin'; import MaigicLink from './src/Screens/MaigicLink'; import Oragnization from './src/Screens/Oragnization'; //import Splash from './src/Screens/Splash'; import SplashScreen from 'react-native-splash-screen'; import {auth} from './firebase/firebase.config'; import NewSignIn from './src/Screens/NewSignIn'; import Signup from './src/Screens/Signup'; import FullfillmentScreen from './FullfillmentScreen'; import Combined from './src/Screens/Combined'; import {Provider} from 'react-redux'; import {store} from './src/redux/store'; import {useSelector} from 'react-redux/es/exports'; import AppNavigation from './src/navigation/AppNavigation'; //const Stack = createNativeStackNavigator(); const App = () => { useEffect(() => { SplashScreen.hide(); }, []); return ( <Provider store={store}> <AppNavigation /> </Provider> ); }; export default App;
Store.tsx
import {configureStore} from '@reduxjs/toolkit'; import user from './slices/user'; export const store = configureStore({ reducer: { user, }, });
user.tsx(Slice)
import {createSlice} from '@reduxjs/toolkit'; import type {PayloadAction} from '@reduxjs/toolkit'; // Define a type for the slice state interface userState { user: string; } // Define the initial state using that type const initialState: userState = { user: '', }; export const userSlice = createSlice({ name: 'counter', // `createSlice` will infer the state type from the `initialState` argument initialState, reducers: { setUser: (state, action) => { state.user = action.payload; }, }, }); export const {setUser} = userSlice.actions; export default userSlice.reducer;
问题原因及解决方法
1. 错误的Redux Hooks导入路径
你从react-redux/es/exports导入useDispatch和useSelector,这属于内部私有路径,会导致Redux上下文识别异常。必须从官方导出路径导入:
// 替换原导入语句 import {useDispatch, useSelector} from 'react-redux';
2. 未在useEffect中注册Auth监听器
直接在组件函数体内调用onAuthStateChanged会导致每次组件渲染都注册新的监听器,不仅浪费资源,还可能在组件未完全挂载到Redux上下文时触发dispatch,引发上下文错误。将逻辑放到useEffect中:
const AppNavigation = () => { const {user} = useSelector(state => state.user); const dispatch = useDispatch(); useEffect(() => { // 注册监听器并保存取消订阅函数 const unsubscribe = onAuthStateChanged(auth, u => { console.log('GOT USER====>', u); dispatch(setUser(u)); }); // 组件卸载时取消监听,避免内存泄漏 return unsubscribe; }, [dispatch]); // ...后续代码 };
3. 重复渲染NavigationContainer
在if/else分支中分别渲染NavigationContainer会创建多个导航实例,干扰Redux上下文传递。将NavigationContainer提到条件判断外部:
const AppNavigation = () => { // ...useSelector和useEffect逻辑 return ( <NavigationContainer> <Stack.Navigator screenOptions={{headerShown: false}}> {user ? ( <> <Stack.Screen name="Organization" component={Oragnization} /> <Stack.Screen name="Combined" component={Combined} /> <Stack.Screen name="FullfillmentScreen" component={FullfillmentScreen} /> </> ) : ( <> <Stack.Screen name="NewSignIn" component={NewSignIn} /> <Stack.Screen name="Signup" component={Signup} /> </> )} </Stack.Navigator> </NavigationContainer> ); };
4. Slice类型定义错误
你的user slice将user定义为string类型,但Firebase返回的是User对象或null,类型不匹配会导致状态异常。修正类型定义:
import {createSlice} from '@reduxjs/toolkit'; import type {PayloadAction} from '@reduxjs/toolkit'; import type {User} from 'firebase/auth'; // 导入Firebase User类型 interface UserState { user: User | null; } const initialState: UserState = { user: null, }; export const userSlice = createSlice({ name: 'user', // 修正slice名称,语义化 initialState, reducers: { setUser: (state, action: PayloadAction<User | null>) => { state.user = action.payload; }, }, }); export const {setUser} = userSlice.actions; export default userSlice.reducer;
总结
按照以上四点修改后,Redux上下文的问题应该能解决,同时代码的规范性和稳定性也会提升。
内容的提问来源于stack exchange,提问作者Muqsit Ali
相关产品推荐
相关产品推荐

