我正在使用 expo 构建一个 React Native 应用程序,并尝试通过上下文向应用程序的其余部分添加身份验证。 应用程序确实正确登录,当表单提交时,我通过 AuthStack 中的 console.log 以及 Firebase 控制台获得确认;但是,为了处理应用程序其余部分的渲染,我似乎陷入了登录屏幕。
useAuth.js 在这里,我创建了一个 use auth hook 并登录 props 以传递到我的 AuthStackScreens 中,以便我可以启动登录。然后将其传递到上下文,以便应用程序可以使用它。
// ... imports
const AuthContext = createContext({})
export function AuthProvider({ children }) {
const [user, setUser] = useState(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
const [loadingInitial, setLoadingInitial] = useState(true)
//implicitly returns an unsubscribe
useEffect(
() =>
onAuthStateChanged(auth, (user) => {
if(user) {
//logged in
setUser(user);
} else {
setUser(null)
}
setLoading(false)
setLoadingInitial(false)
}),
[]
);
const signIn = async(userEmail, userPassword) => {
try {
const userCredential = await signInWithEmailAndPassword(auth, userEmail, userPassword );
setUser(userCredential.user);
}
catch (error) {
console.error('error Signing in ', error.message);
}
}
const memoedValue = useMemo(() => ({
user,
loading,
signIn
}), [user, loading, error ] )
console.log("auth" , user)
return (
<AuthContext.Provider
value={memoedValue}
>
{!loadingInitial && children}
</AuthContext.Provider>
)
}
export default function useAuth() {
return useContext(AuthContext);
}
const styles = StyleSheet.create({})
// ... (imports)
const AuthStack = createNativeStackNavigator();
//Schema to send data for auth
export const loginSchema = yup.object().shape({
email: yup
.string()
.email("Invalid Email Format")
.required("Email is a Required Field"),
password: yup.string().required("Password is a Required field"),
})
// Handle Error
function ErrorText ({ name, errors}) {
if (!errors) {
return null
}
return (
<View style={{paddingLeft: 8, color: "red"}}>
{errors[name] && (
<Text style={{color:'#d81010'}}>{errors?.[name]?.message}</Text>
)}
</View>
);
};
//Receive and deploy error
const ErrorAlert = ({title, message}) =>
Alert.alert(title, message, [
{text: "OK", onPress: () => console.log("ok Pressed")}
])
//Condense setting data in state
export function LoginScreen({navigation}) {
const{ signIn, loading } = useAuth()
//stores form inputs
const {
register,
setValue,
getValues,
handleSubmit,
// control,
// reset,
formState: {errors},
} = useForm({
resolver: yupResolver(loginSchema),
defaultValues: {
email: '',
password: "",
},
});
useEffect (() => {
register("email");
register("password");
}, [] )
// handles log in
async function doLogin (data) {
const { email, password} = data
console.log(data)
try {
await signIn(email, password)
console.log("signed In!!!")
// commented out navigation as per react navigation auth flow discourages manual navigation after on log in, should be handled by authcontext
// navigation.navigate('HomeTabs')
}
catch (error) {
Alert.alert('Error Logging In', error.message);
}
}
// unused function
function onConfirmHandler() {
// Confirm sign in
//navigate to home
// navigation.navigate(HomeScreen)
}
function onPressSignUp () {
navigation.navigate("SignUpScreen")
}
return (
<View>
<Text> Email</Text>
<TextInput
id="email"
textContentType='emailAddress'
autoCapitalize='none'
style={styles.input}
onChangeText={(text)=> setValue("email", text)}
/>
<ErrorText name="email" errors={errors}> </ErrorText>
<Text> Password</Text>
<TextInput
id="password"
textContentType='password'
secureTextEntry={true}
style={styles.input}
autoCapitalize='none'
onChangeText={(text)=> setValue("password", text)}
/>
<ErrorText name="password" errors={errors}> </ErrorText>
<View style={styles.buttonContainer}>
<Button style={styles.button}onPress={handleSubmit(doLogin)} > Log In </Button>
<Text style={styles.buttonText}> Don't have an account? </Text>
<Button style={styles.button} onPress={onPressSignUp} > Create Account </Button>
</View>
</View>
)
}
//sign up currently work in progress after log in becomes successful
export function SignUpScreen({navigation}) {
...
function AuthStackScreens() {
return <AuthStack.Navigator >
<AuthStack.Screen name="LoginScreen" component={LoginScreen}/>
<AuthStack.Screen name="SignUpScreen" component={SignUpScreen}/>
{/* navigate to profilecreate screen? */}
</AuthStack.Navigator>
}
export default AuthStackScreens
const styles = StyleSheet.create({
// ... styling
})
这里登录当前正常工作,表单提交,useAuth.js 中的 console.log 触发,我确实看到我获取了所有用户数据。
// ...imports
const MainStack = createNativeStackNavigator();
const BottomTab = createBottomTabNavigator();
const ProfileStack = createNativeStackNavigator();
function HomeTabs() {
return (
<BottomTab.Navigator screenOptions={{ headerShown: false }}>
<BottomTab.Screen
name="HomeScreen"
component={HomeScreen}
options={{
tabBarIcon: ({ color, size }) => <Ionicons name="home" color={color} size={size} />,
headerShown: false,
}}
/>
<BottomTab.Screen
name="Profile"
component={ProfileStackScreens}
options={{
tabBarIcon: ({ color, size }) => <Ionicons name="person" color={color} size={size} />,
headerShown: false,
}}
/>
</BottomTab.Navigator>
);
}
function ProfileStackScreens() {
return (
<ProfileStack.Navigator>
<ProfileStack.Screen name="ProfileScreen" component={ProfileScreen} />
</ProfileStack.Navigator>
);
}
export default function App() {
const { user, loading } = useAuth();
// console.log returns undefined for user, fires first when app builds
console.log(user, loading)
if (loading) {
return <View><Text>loading. .. .</Text></View>;
}
return (
<SafeAreaView style={styles.screen}>
<AuthProvider>
<NavigationContainer>
<UsersContextProvider>
<MainStack.Navigator>
{user ? (
<>
<MainStack.Screen name="HomeTabs" component={HomeTabs} options={{ headerShown: false }} />
<MainStack.Screen name="CardDetails" component={CardDetails} />
<MainStack.Screen name="Profile" component={ProfileStackScreens} />
<MainStack.Screen name="ProfileCreateScreen" component={ProfileCreateScreen} />
</>
) : (
<MainStack.Screen name="Auth" component={AuthStackScreens} options={{ headerShown: false }} />
)}
</MainStack.Navigator>
</UsersContextProvider>
</NavigationContainer>
</AuthProvider>
</SafeAreaView>
);
}
现在这就是我认为问题所在的地方,我正在使用嵌套导航器,我认为问题在于我如何尝试使 AuthProvider 成为一个更高的订单组件。我认为我做得正确。我怀疑问题在于,当其他组件登录时,app.js 中的 useAuth 挂钩不会更新。我尝试在 useAuth.js 中使用 useReducer 进行重构,但这也不起作用。经过几个小时的研究,我想知道是否还有其他人可以提供新的视角。谢谢你。
编辑:
因此,将导航组件分成单独的文件后,useAuth 检查发生在 MainStackScreen 组件文件中,而不是 app.js 中,这样应用程序可以首先触发并正确查找其他组件。进行这些更改后,登录即可正确进入主屏幕。