休斯顿,我们有问题。
我一直不太了解Redux是如何工作的。到了为我的react原生应用程序进行身份验证流程的时候,我找到了一个使用reducer的教程,复制了它,它就工作了。。。我一直很困惑为什么代码能工作,因为我看不到我在";登录状态"变量插入上下文。。。但它(在ios上(工作,所以我顺其自然。
但今天,当我尝试网络版的react原生应用程序时,它成了一个问题。出于某种原因,我也不理解,声明一个不带"的变量是可以接受的;const";在react原生ios/android中,但不在web中。如果要修复我用类型声明声明redux状态的问题(如图所示(,它就不再适用于嵌套函数:
**const** [loginState, dispatch] = React.useReducer(LoginReducer, {isLoading: false, isSignout: false, userToken: null, isVerified: false})
请帮助我理解
这是我的App.js:
import * as React from 'react';
import LoginReducer from './Reducer/LoginReducer';
import AppContainer from './Navigators/AppNavigationContainer.js'
import {loadLocale, strings2} from './assets/locales/i18n'
import {AppLoading} from 'expo'
global.AuthContext = React.createContext();
global.LanguageContext = React.createContext({
language: 'es',
setLanguage:()=>{}
})
export default function App ({navigation}) {
//LanguageContext
const [languageReady, setLanguageReady] = React.useState(false);
const [language,setLanguage] = React.useState('es');
//Load language
const initLang = async () => {
const currentLanguage = await loadLocale()
setLanguage(currentLanguage)
};
[loginState, dispatch] = React.useReducer(LoginReducer, {isLoading: false, isSignout: false, userToken: null, isVerified: false})
global.authContext = React.useMemo(() => ({
signIn: () => {
dispatch({ type: 'SIGN_UP' })
dispatch({ type: 'SIGN_IN', token: 'dummy-token' });
AsyncStorage.setItem('userToken', 'dummy-token' )
},
signOut: () => {
AsyncStorage.removeItem('userToken')
dispatch({ type: 'SIGN_OUT' })
},
signUp: () => {
dispatch({ type: 'SIGN_IN', token: 'dummy-token' })
AsyncStorage.setItem('userToken', 'dummy-token')
},
}),[]);
return(
<>
{languageReady ? (
<LanguageContext.Provider value={{language, setLanguage}}>
<AppContainer/>
</LanguageContext.Provider>
) : (
<AppLoading
startAsync={initLang()}
onFinish={setLanguageReady(true)}/>
)}
</>
)
}
这里是我的应用导航器;登录状态"应该可以进行身份验证流。
import * as React from 'react';
import { NavigationContainer } from '@react-navigation/native';
import { createStackNavigator } from '@react-navigation/stack';
import LoadingScreen from '../Screens/LoadingScreen.js'
import SignInScreen from '../Screens/SignInScreen.js'
import VerifyEmail from '../Screens/VerifyEmail.js'
import MainAppTab from './MainAppTab.js'
const Stack = createStackNavigator();
export default function AppContainer () {
return (
<AuthContext.Provider value={global.authContext}>
<NavigationContainer>
<Stack.Navigator
initialRouteName='SignIn'
headerMode='none'
>
{loginState.isLoading ? (<>
<Stack.Screen name='Loading' component={LoadingScreen}/>
</>) : loginState.userToken == null ? (<>
<Stack.Screen name='SignIn' component={SignInScreen}/>
</>) : loginState.isVerified === false ? (<>
<Stack.Screen name='Verify' component={VerifyEmail}/>
</>) : (
<Stack.Screen name='Main' component={MainAppTab}/>
)}
</Stack.Navigator>
</NavigationContainer>
</AuthContext.Provider>
)
}
如果不使用const
、var
或let
声明变量,则该变量将位于全局作用域中。这就是为什么您的状态和调度功能在任何地方都可用。未声明关键字的const
、var
、let
和都具有不同的作用域。阅读关于这个问题的JavaScript作用域、mozilla开发人员网站和w3schools的更多信息。
为了使state和dispatch函数在其他地方可用,您需要将值传递给它需要去的组件。在您的情况下,您需要把它们传递给AppContainer组件。
下面是一个例子:
App.js:
import React from 'react';
import TestAppContainer from "./TestAppContainer";
const LOGIN = "LOGIN";
// This dummy reducer just returns the current state.
// Your reducer probably does something useful :)
const TestAppReducer = (state, action) => {
switch (action.type) {
case LOGIN:
return state;
default:
return state;
}
};
export default function App() {
const [loginState, dispatch] = React.useReducer(TestAppReducer, {isLoading: false, isSignout: false, userToken: null, isVerified: false})
return (
<TestAppContainer loginState={loginState} dispatch={dispatch} />
);
}
TestAppContainer.js:
import React from "react";
import {View, Text, Button} from "react-native";
const TestAppContainer = props => {
const { loginState, dispatch } = props;
const onPressHandler = () => {
console.log(loginState);
console.log(dispatch !== undefined);
}
return (
<View style={{flex: 1, justifyContent: "center", alignItems: "center"}}>
<Text>Test App WOW!</Text>
<Button title={"Press me."} onPress={onPressHandler} />
</View>
);
}
export default TestAppContainer;