无法在 React Native 中导航
Unable to Navigate in React Native
我正在尝试将导航分派到另一个屏幕以获取恢复密码,问题是我使用了一个用于身份验证的旧代码,但它有一个使用 form reducer 的功能,这不允许我导航给出错误:
ReferenceError:找不到变量:inputChangeHandler
这是我的代码:
import React, { useState, useReducer, useCallback, useEffect } from 'react';
import { ScrollView, View, KeyboardAvoidingView, StyleSheet, Button, ActivityIndicator, Alert, Image, Text, TouchableNativeFeedback, TouchableOpacity, Platform } from 'react-native';
import { LinearGradient } from 'expo-linear-gradient';
import { useDispatch } from 'react-redux';
import Input from '../components/UI/Input';
import Card from '../components/UI/Card';
import Colors from '../constants/Colors';
import * as authActions from '../store/actions/auth';
const FORM_INPUT_UPDATE = 'FORM_INPUT_UPDATE';
const formReducer = (state, action) => {
if (action.type === FORM_INPUT_UPDATE) {
const updatedValues = {
...state.inputValues,
[action.input]: action.value
};
const updatedValidities = {
...state.inputValidities,
[action.input]: action.isValid
};
let updatedFormIsValid = true;
for (const key in updatedValidities) {
updatedFormIsValid = updatedFormIsValid && updatedValidities[key];
}
return {
formIsValid: updatedFormIsValid,
inputValidities: updatedValidities,
inputValues: updatedValues
};
}
return state;
};
const AuthScreen = props => {
let TouchableCmp = TouchableOpacity;
if (Platform.OS === 'android' && Platform.Version >= 21) {
TouchableCmp = TouchableNativeFeedback;
}
const [isLoading, setIsLoading] = useState(false);
const [error, setError] = useState();
const [isSignup, setIsSignup] = useState(false);
const dispatch = useDispatch();
const [formState, dispatchFormState] = useReducer(formReducer, {
inputValues: {
email: '',
password: '',
},
inputValidities: {
email: false,
password:false,
},
formIsValid: false,
});
useEffect(() => {
if (error) {
Alert.alert('Ah Ocurrido un Error', error, [{ text: 'Ok' }]);
}
}, [error]);
const authHandler = async () => {
let action;
if (isSignup) {
action =
authActions.signup(
formState.inputValues.email,
formState.inputValues.password,
)
} else {
action =
authActions.login(
formState.inputValues.email,
formState.inputValues.password,
)
}
setError(null);
setIsLoading(true);
try {
await dispatch(action);
//props.navigation.navigate('Shop');
} catch (err) {
setError(err.message);
setIsLoading(false);
}
};
const inputChangeHandler = useCallback(
(inputIdentifier, inputValue, inputValidity) => {
dispatchFormState({
type: FORM_INPUT_UPDATE,
value: inputValue,
isValid: inputValidity,
input: inputIdentifier
});
},
[dispatchFormState]
);
const changeRecover = () => {
props.navigation.navigate('Recover');
};
return (
<KeyboardAvoidingView
behavior="height"
keyboardVerticalOffset={50}
style={styles.screen}>
<LinearGradient colors={[Colors.background, Colors.primary]} style={styles.gradient}>
<View style={styles.imageCircle}>
<Image
resizeMode="cover"
style={{ flex: 1 }}
source={{ uri: 'https://media.api-sports.io/football/teams/4299.png' }}
/>
</View>
<Card style={styles.authContainer}>
<ScrollView>
<Input
id="email"
label="Correo"
keyboardType="email-address"
required
email
autoCapitalize="none"
errorText="Porfavor introduzca una direccion de Correo Valida"
onInputChange={inputChangeHandler}
initialValue=''
/>
<Input
id="password"
label="Contraseña"
keyboardType="default"
secureTextEntry
required
minLength={5}
autoCapitalize="none"
errorText="Porfavor introduzca una Contraseña Valida"
onInputChange={inputChangeHandler}
initialValue=''
/>
<View style={styles.buttonContainer}>
{isLoading ? <ActivityIndicator size="small" color={Colors.primary} /> : <Button
title={isSignup ? 'Registrarse' : 'Acceder'}
color={Colors.primary}
onPress={authHandler}
/>}
</View>
<View style={styles.buttonContainer}>
<Button
title={`Cambiar a ${isSignup ? 'Acceder' : 'Registrarse'}`}
color={Colors.accent}
onPress={() => {
setIsSignup(prevState => !prevState);
}}
/>
</View>
{isSignup ?
null
:<View style={styles.buttonContainer}>
<Button
title={'Olvide mi Contraseña'}
color={Colors.accent}
onPress={changeRecover}
/>
</View>}
</ScrollView>
</Card>
</LinearGradient>
</KeyboardAvoidingView>
);
};
export const screenOptions = {
headerTitle: 'Ingrese',
}
const styles = StyleSheet.create({
screen: {
//flex: 1,
},
authContainer: {
width: '80%',
maxWidth: 400,
height: '50%',
maxHeight: 400,
padding: 20,
},
imageCircle: {
width: '50%',
height: '30%',
// backgroundColor: 'white',
// borderRadius: 25,
padding: 8,
// borderWidth: 2,
// borderColor: 'rgba(21,21,21,0.2)',
justifyContent: 'center',
alignContent: 'center',
marginBottom: 10,
},
buttonContainer: {
marginTop: 15,
borderRadius: 50,
},
gradient: {
width: '100%',
height: '100%',
justifyContent: 'center',
alignItems: 'center',
}
});
export default AuthScreen;
我想要的只是在单击按钮时能够更改页面(顺便说一下,我希望将其作为常规超链接,而不是将其视为按钮)。
但不想避免我目前拥有的登录或注册功能。
有什么想法吗?
对于 12 位查看此内容的人post。
我找到了答案,最后我将变量 Action 更改为状态变量,将初始状态保留为 'Acceder' 用于登录,在更改按钮上我检查了当前状态,如果它是 'Acceder' 我变成了 'Registrarse' 这是为了注册,最后当点击忘记密码时 link 我将状态更改为 'Olvido Contraseña' 然后在我刚刚评估的身份验证处理程序中动作状态并相应地调度动作。
代码在这里:
import React, { useState, useReducer, useCallback, useEffect } from 'react';
import { ScrollView, View, KeyboardAvoidingView, StyleSheet, Button, ActivityIndicator, Alert, Image, Text, TouchableNativeFeedback, TouchableOpacity, Platform } from 'react-native';
import { LinearGradient } from 'expo-linear-gradient';
import { useDispatch } from 'react-redux';
import Input from '../components/UI/Input';
import Card from '../components/UI/Card';
import Colors from '../constants/Colors';
import * as authActions from '../store/actions/auth';
import { set } from 'react-native-reanimated';
const FORM_INPUT_UPDATE = 'FORM_INPUT_UPDATE';
const formReducer = (state, action) => {
if (action.type === FORM_INPUT_UPDATE) {
const updatedValues = {
...state.inputValues,
[action.input]: action.value
};
const updatedValidities = {
...state.inputValidities,
[action.input]: action.isValid
};
let updatedFormIsValid = true;
for (const key in updatedValidities) {
updatedFormIsValid = updatedFormIsValid && updatedValidities[key];
}
return {
formIsValid: updatedFormIsValid,
inputValidities: updatedValidities,
inputValues: updatedValues
};
}
return state;
};
const AuthScreen = props => {
let TouchableCmp = TouchableOpacity;
if (Platform.OS === 'android' && Platform.Version >= 21) {
TouchableCmp = TouchableNativeFeedback;
}
const [isLoading, setIsLoading] = useState(false);
const [error, setError] = useState();
const [isSignup, setIsSignup] = useState(false);
const [isAction, setIsAction] = useState('Acceder');
const dispatch = useDispatch();
const [formState, dispatchFormState] = useReducer(formReducer, {
inputValues: {
email: '',
password: '',
},
inputValidities: {
email: false,
password: false,
},
formIsValid: false,
});
useEffect(() => {
if (error) {
Alert.alert('Ah Ocurrido un Error', error, [{ text: 'Ok' }]);
}
}, [error]);
const authHandler = async () => {
let action;
if (isAction === 'Registrarse') {
action =
authActions.signup(
formState.inputValues.email,
formState.inputValues.password,
)
} else if (isAction === 'Acceder') {
action =
authActions.login(
formState.inputValues.email,
formState.inputValues.password,
)
} else {
action =
authActions.recoverPassword(
formState.inputValues.email
)
}
setError(null);
setIsLoading(true);
try {
await dispatch(action);
if(isAction === 'Cambiar Contraseña'){
setIsLoading(false);
setIsAction('Acceder');
}
//props.navigation.navigate('Shop');
} catch (err) {
setError(err.message);
setIsLoading(false);
}
};
const inputChangeHandler = useCallback(
(inputIdentifier, inputValue, inputValidity) => {
dispatchFormState({
type: FORM_INPUT_UPDATE,
value: inputValue,
isValid: inputValidity,
input: inputIdentifier
});
},
[dispatchFormState]
);
return (
<KeyboardAvoidingView
behavior="height"
keyboardVerticalOffset={50}
style={styles.screen}>
<LinearGradient colors={[Colors.background, Colors.primary]} style={styles.gradient}>
<View style={styles.imageCircle}>
<Image
resizeMode="cover"
style={{ flex: 1 }}
source={{ uri: 'https://media.api-sports.io/football/teams/4299.png' }}
/>
</View>
<Card style={styles.authContainer}>
<ScrollView>
<Input
id="email"
label="Correo"
keyboardType="email-address"
required
email
autoCapitalize="none"
errorText="Porfavor introduzca una direccion de Correo Valida"
onInputChange={inputChangeHandler}
initialValue=''
/>
{isAction === 'Cambiar Contraseña' ?
null :
<Input
id="password"
label="Contraseña"
keyboardType="default"
secureTextEntry
required
minLength={5}
autoCapitalize="none"
errorText="Porfavor introduzca una Contraseña Valida"
onInputChange={inputChangeHandler}
initialValue=''
/>}
<View style={styles.buttonContainer}>
{isLoading ?
<ActivityIndicator size="small" color={Colors.primary} />
: <Button
title={isAction}
color={Colors.primary}
onPress={authHandler}
/>}
</View>
<View style={styles.buttonContainer}>
<Button
title={`Cambiar a ${isAction === 'Acceder' ? 'Registrarse' : 'Acceder'}`}
color={Colors.accent}
onPress={() => {
//setIsSignup(prevState => !prevState);
if (isAction === 'Registrarse') {
setIsAction('Acceder')
} else {
setIsAction('Registrarse')
}
}}
/>
</View>
{isAction === 'Registrarse' || isAction === 'Cambiar Contraseña' ?
null
:
<View style={styles.centerView}>
<Text style={{ color: 'blue' }}
onPress={() => {
setIsAction('Cambiar Contraseña');
}}>
Olvide mi Contraseña
</Text>
</View>
}
</ScrollView>
</Card>
</LinearGradient>
</KeyboardAvoidingView>
);
};
export const screenOptions = {
headerTitle: 'Alianza F.C.',
}
const styles = StyleSheet.create({
screen: {
//flex: 1,
},
authContainer: {
width: '80%',
maxWidth: 400,
height: '50%',
maxHeight: 400,
padding: 20,
},
imageCircle: {
width: '50%',
height: '30%',
// backgroundColor: 'white',
// borderRadius: 25,
padding: 8,
// borderWidth: 2,
// borderColor: 'rgba(21,21,21,0.2)',
justifyContent: 'center',
alignContent: 'center',
marginBottom: 10,
},
buttonContainer: {
marginTop: 15,
borderRadius: 50,
},
gradient: {
width: '100%',
height: '100%',
justifyContent: 'center',
alignItems: 'center',
},
centerView: {
justifyContent: 'center',
alignItems: 'center',
marginTop: 10,
}
});
export default AuthScreen;
我正在尝试将导航分派到另一个屏幕以获取恢复密码,问题是我使用了一个用于身份验证的旧代码,但它有一个使用 form reducer 的功能,这不允许我导航给出错误:
ReferenceError:找不到变量:inputChangeHandler
这是我的代码:
import React, { useState, useReducer, useCallback, useEffect } from 'react';
import { ScrollView, View, KeyboardAvoidingView, StyleSheet, Button, ActivityIndicator, Alert, Image, Text, TouchableNativeFeedback, TouchableOpacity, Platform } from 'react-native';
import { LinearGradient } from 'expo-linear-gradient';
import { useDispatch } from 'react-redux';
import Input from '../components/UI/Input';
import Card from '../components/UI/Card';
import Colors from '../constants/Colors';
import * as authActions from '../store/actions/auth';
const FORM_INPUT_UPDATE = 'FORM_INPUT_UPDATE';
const formReducer = (state, action) => {
if (action.type === FORM_INPUT_UPDATE) {
const updatedValues = {
...state.inputValues,
[action.input]: action.value
};
const updatedValidities = {
...state.inputValidities,
[action.input]: action.isValid
};
let updatedFormIsValid = true;
for (const key in updatedValidities) {
updatedFormIsValid = updatedFormIsValid && updatedValidities[key];
}
return {
formIsValid: updatedFormIsValid,
inputValidities: updatedValidities,
inputValues: updatedValues
};
}
return state;
};
const AuthScreen = props => {
let TouchableCmp = TouchableOpacity;
if (Platform.OS === 'android' && Platform.Version >= 21) {
TouchableCmp = TouchableNativeFeedback;
}
const [isLoading, setIsLoading] = useState(false);
const [error, setError] = useState();
const [isSignup, setIsSignup] = useState(false);
const dispatch = useDispatch();
const [formState, dispatchFormState] = useReducer(formReducer, {
inputValues: {
email: '',
password: '',
},
inputValidities: {
email: false,
password:false,
},
formIsValid: false,
});
useEffect(() => {
if (error) {
Alert.alert('Ah Ocurrido un Error', error, [{ text: 'Ok' }]);
}
}, [error]);
const authHandler = async () => {
let action;
if (isSignup) {
action =
authActions.signup(
formState.inputValues.email,
formState.inputValues.password,
)
} else {
action =
authActions.login(
formState.inputValues.email,
formState.inputValues.password,
)
}
setError(null);
setIsLoading(true);
try {
await dispatch(action);
//props.navigation.navigate('Shop');
} catch (err) {
setError(err.message);
setIsLoading(false);
}
};
const inputChangeHandler = useCallback(
(inputIdentifier, inputValue, inputValidity) => {
dispatchFormState({
type: FORM_INPUT_UPDATE,
value: inputValue,
isValid: inputValidity,
input: inputIdentifier
});
},
[dispatchFormState]
);
const changeRecover = () => {
props.navigation.navigate('Recover');
};
return (
<KeyboardAvoidingView
behavior="height"
keyboardVerticalOffset={50}
style={styles.screen}>
<LinearGradient colors={[Colors.background, Colors.primary]} style={styles.gradient}>
<View style={styles.imageCircle}>
<Image
resizeMode="cover"
style={{ flex: 1 }}
source={{ uri: 'https://media.api-sports.io/football/teams/4299.png' }}
/>
</View>
<Card style={styles.authContainer}>
<ScrollView>
<Input
id="email"
label="Correo"
keyboardType="email-address"
required
email
autoCapitalize="none"
errorText="Porfavor introduzca una direccion de Correo Valida"
onInputChange={inputChangeHandler}
initialValue=''
/>
<Input
id="password"
label="Contraseña"
keyboardType="default"
secureTextEntry
required
minLength={5}
autoCapitalize="none"
errorText="Porfavor introduzca una Contraseña Valida"
onInputChange={inputChangeHandler}
initialValue=''
/>
<View style={styles.buttonContainer}>
{isLoading ? <ActivityIndicator size="small" color={Colors.primary} /> : <Button
title={isSignup ? 'Registrarse' : 'Acceder'}
color={Colors.primary}
onPress={authHandler}
/>}
</View>
<View style={styles.buttonContainer}>
<Button
title={`Cambiar a ${isSignup ? 'Acceder' : 'Registrarse'}`}
color={Colors.accent}
onPress={() => {
setIsSignup(prevState => !prevState);
}}
/>
</View>
{isSignup ?
null
:<View style={styles.buttonContainer}>
<Button
title={'Olvide mi Contraseña'}
color={Colors.accent}
onPress={changeRecover}
/>
</View>}
</ScrollView>
</Card>
</LinearGradient>
</KeyboardAvoidingView>
);
};
export const screenOptions = {
headerTitle: 'Ingrese',
}
const styles = StyleSheet.create({
screen: {
//flex: 1,
},
authContainer: {
width: '80%',
maxWidth: 400,
height: '50%',
maxHeight: 400,
padding: 20,
},
imageCircle: {
width: '50%',
height: '30%',
// backgroundColor: 'white',
// borderRadius: 25,
padding: 8,
// borderWidth: 2,
// borderColor: 'rgba(21,21,21,0.2)',
justifyContent: 'center',
alignContent: 'center',
marginBottom: 10,
},
buttonContainer: {
marginTop: 15,
borderRadius: 50,
},
gradient: {
width: '100%',
height: '100%',
justifyContent: 'center',
alignItems: 'center',
}
});
export default AuthScreen;
我想要的只是在单击按钮时能够更改页面(顺便说一下,我希望将其作为常规超链接,而不是将其视为按钮)。
但不想避免我目前拥有的登录或注册功能。
有什么想法吗?
对于 12 位查看此内容的人post。
我找到了答案,最后我将变量 Action 更改为状态变量,将初始状态保留为 'Acceder' 用于登录,在更改按钮上我检查了当前状态,如果它是 'Acceder' 我变成了 'Registrarse' 这是为了注册,最后当点击忘记密码时 link 我将状态更改为 'Olvido Contraseña' 然后在我刚刚评估的身份验证处理程序中动作状态并相应地调度动作。
代码在这里:
import React, { useState, useReducer, useCallback, useEffect } from 'react';
import { ScrollView, View, KeyboardAvoidingView, StyleSheet, Button, ActivityIndicator, Alert, Image, Text, TouchableNativeFeedback, TouchableOpacity, Platform } from 'react-native';
import { LinearGradient } from 'expo-linear-gradient';
import { useDispatch } from 'react-redux';
import Input from '../components/UI/Input';
import Card from '../components/UI/Card';
import Colors from '../constants/Colors';
import * as authActions from '../store/actions/auth';
import { set } from 'react-native-reanimated';
const FORM_INPUT_UPDATE = 'FORM_INPUT_UPDATE';
const formReducer = (state, action) => {
if (action.type === FORM_INPUT_UPDATE) {
const updatedValues = {
...state.inputValues,
[action.input]: action.value
};
const updatedValidities = {
...state.inputValidities,
[action.input]: action.isValid
};
let updatedFormIsValid = true;
for (const key in updatedValidities) {
updatedFormIsValid = updatedFormIsValid && updatedValidities[key];
}
return {
formIsValid: updatedFormIsValid,
inputValidities: updatedValidities,
inputValues: updatedValues
};
}
return state;
};
const AuthScreen = props => {
let TouchableCmp = TouchableOpacity;
if (Platform.OS === 'android' && Platform.Version >= 21) {
TouchableCmp = TouchableNativeFeedback;
}
const [isLoading, setIsLoading] = useState(false);
const [error, setError] = useState();
const [isSignup, setIsSignup] = useState(false);
const [isAction, setIsAction] = useState('Acceder');
const dispatch = useDispatch();
const [formState, dispatchFormState] = useReducer(formReducer, {
inputValues: {
email: '',
password: '',
},
inputValidities: {
email: false,
password: false,
},
formIsValid: false,
});
useEffect(() => {
if (error) {
Alert.alert('Ah Ocurrido un Error', error, [{ text: 'Ok' }]);
}
}, [error]);
const authHandler = async () => {
let action;
if (isAction === 'Registrarse') {
action =
authActions.signup(
formState.inputValues.email,
formState.inputValues.password,
)
} else if (isAction === 'Acceder') {
action =
authActions.login(
formState.inputValues.email,
formState.inputValues.password,
)
} else {
action =
authActions.recoverPassword(
formState.inputValues.email
)
}
setError(null);
setIsLoading(true);
try {
await dispatch(action);
if(isAction === 'Cambiar Contraseña'){
setIsLoading(false);
setIsAction('Acceder');
}
//props.navigation.navigate('Shop');
} catch (err) {
setError(err.message);
setIsLoading(false);
}
};
const inputChangeHandler = useCallback(
(inputIdentifier, inputValue, inputValidity) => {
dispatchFormState({
type: FORM_INPUT_UPDATE,
value: inputValue,
isValid: inputValidity,
input: inputIdentifier
});
},
[dispatchFormState]
);
return (
<KeyboardAvoidingView
behavior="height"
keyboardVerticalOffset={50}
style={styles.screen}>
<LinearGradient colors={[Colors.background, Colors.primary]} style={styles.gradient}>
<View style={styles.imageCircle}>
<Image
resizeMode="cover"
style={{ flex: 1 }}
source={{ uri: 'https://media.api-sports.io/football/teams/4299.png' }}
/>
</View>
<Card style={styles.authContainer}>
<ScrollView>
<Input
id="email"
label="Correo"
keyboardType="email-address"
required
email
autoCapitalize="none"
errorText="Porfavor introduzca una direccion de Correo Valida"
onInputChange={inputChangeHandler}
initialValue=''
/>
{isAction === 'Cambiar Contraseña' ?
null :
<Input
id="password"
label="Contraseña"
keyboardType="default"
secureTextEntry
required
minLength={5}
autoCapitalize="none"
errorText="Porfavor introduzca una Contraseña Valida"
onInputChange={inputChangeHandler}
initialValue=''
/>}
<View style={styles.buttonContainer}>
{isLoading ?
<ActivityIndicator size="small" color={Colors.primary} />
: <Button
title={isAction}
color={Colors.primary}
onPress={authHandler}
/>}
</View>
<View style={styles.buttonContainer}>
<Button
title={`Cambiar a ${isAction === 'Acceder' ? 'Registrarse' : 'Acceder'}`}
color={Colors.accent}
onPress={() => {
//setIsSignup(prevState => !prevState);
if (isAction === 'Registrarse') {
setIsAction('Acceder')
} else {
setIsAction('Registrarse')
}
}}
/>
</View>
{isAction === 'Registrarse' || isAction === 'Cambiar Contraseña' ?
null
:
<View style={styles.centerView}>
<Text style={{ color: 'blue' }}
onPress={() => {
setIsAction('Cambiar Contraseña');
}}>
Olvide mi Contraseña
</Text>
</View>
}
</ScrollView>
</Card>
</LinearGradient>
</KeyboardAvoidingView>
);
};
export const screenOptions = {
headerTitle: 'Alianza F.C.',
}
const styles = StyleSheet.create({
screen: {
//flex: 1,
},
authContainer: {
width: '80%',
maxWidth: 400,
height: '50%',
maxHeight: 400,
padding: 20,
},
imageCircle: {
width: '50%',
height: '30%',
// backgroundColor: 'white',
// borderRadius: 25,
padding: 8,
// borderWidth: 2,
// borderColor: 'rgba(21,21,21,0.2)',
justifyContent: 'center',
alignContent: 'center',
marginBottom: 10,
},
buttonContainer: {
marginTop: 15,
borderRadius: 50,
},
gradient: {
width: '100%',
height: '100%',
justifyContent: 'center',
alignItems: 'center',
},
centerView: {
justifyContent: 'center',
alignItems: 'center',
marginTop: 10,
}
});
export default AuthScreen;