React Native跳转注册页报props.route未定义TypeError修复
报错根因
- 组件参数解构错误:React Navigation 向注册页面传入的顶层props仅包含
navigation、route属性,SignUpScreen中写的({navigation,route,props})相当于尝试从props中解构不存在的props字段,后续访问props.route时自然拿到undefined。 - 跳转时未传参:Main页面点击「Dont have an account ?」跳转时,没有向SignUpScreen传递
type参数,即使props写法正确,访问route.params.type也会因为params为空报错。 - 逻辑写法无效:Main页面Doctor、User按钮的onPress使用逗号表达式,既没有保存选中的用户身份,也没有传递参数,完全不生效;且页面缺少邮箱、密码输入框,原有登录逻辑根本无法获取输入值。
- 页面分支缺失:SignUpScreen仅写了
type=='Doctor'时的返回UI,普通用户身份进入页面时会出现白屏;接口请求异常时未重置loading状态,会导致页面永久卡死在加载态。
代码修复方案
1. 修正SignUpScreen代码
首先修正组件入参,移除不存在的props解构项,给参数加空值保护,补全普通用户分支,修正所有错误的props引用:
import React,{useState, useEffect} from 'react' import { View, Text ,Image,StyleSheet,KeyboardAvoidingView,TouchableOpacity,ActivityIndicator,ScrollView} from 'react-native' import { TextInput,Button } from 'react-native-paper'; import {launchImageLibrary} from 'react-native-image-picker'; import storage from '@react-native-firebase/storage' import auth from '@react-native-firebase/auth' import firestore from '@react-native-firebase/firestore' // 组件入参直接解构navigation和route,不要加多余的props字段 const SignupScreen =({navigation,route}) =>{ const [email,setEmail] = useState('') const [name,setName] = useState('') const [password,setPassword] = useState('') const [image,setImage] = useState(null) const [showNext,setShowNext] = useState(false) const [loading,setLoading] = useState(false) if(loading){ return <ActivityIndicator size="large" color="#00ff00" /> } const userSignup = async ()=>{ setLoading(true) if(!email || !password || !name){ alert("please add all the field") setLoading(false) return } try{ const result = await auth().createUserWithEmailAndPassword(email,password) firestore().collection('users').doc(result.user.uid).set({ name:name, email:result.user.email, uid:result.user.uid, pic:image, status:"online", type: type }) setLoading(false) }catch(err){ setLoading(false) alert("something went wrong") } } // 用可选链做安全访问,设置默认值为普通用户,避免参数缺失时报错 const type=route?.params?.type || 'User' useEffect(()=>{ // 原代码调用了未定义的allUsers函数,需自行补全对应逻辑 // allUsers() },[]) // 医生端注册UI if(type=='Doctor'){ return ( <ScrollView> <KeyboardAvoidingView behavior="position"> <View style={styles.box1}> <Image style={styles.img} source={require('../assets/hee.png')} /> </View> <View style={styles.box2}> {!showNext && <> <TextInput label="Email" value={email} onChangeText={(text)=>setEmail(text)} mode="outlined" /> <TextInput label="password" mode="outlined" value={password} onChangeText={(text)=>setPassword(text)} secureTextEntry /> <TextInput label="Full Name" mode="outlined" /> <TextInput label="Address" mode="outlined" /> <TextInput label="Contact Number" mode="outlined" keyboardType='numeric' /> </> } {showNext ? <> <TextInput label="Name" value={name} onChangeText={(text)=>setName(text)} mode="outlined" /> <Button mode="contained" style={{marginTop:20}} onPress={()=>userSignup()} >Signup</Button> <TouchableOpacity style={{textAlign:"center", marginTop:25,marginLeft:115}} onPress={()=>navigation.goBack()}> <Text>Go Back</Text> </TouchableOpacity> </> : <Button style={{marginTop:20}} mode="contained" onPress={()=>setShowNext(true)} >Next</Button> } {/* 替换原错误的props.navigation引用 */} <TouchableOpacity onPress={()=>navigation.goBack()}><Text style={{textAlign:"center", marginTop:25}}>Already have an account ?</Text></TouchableOpacity> </View> </KeyboardAvoidingView> </ScrollView> ) } // 补全普通用户注册UI,可根据业务需求增减字段 return ( <ScrollView> <KeyboardAvoidingView behavior="position"> <View style={styles.box1}> <Image style={styles.img} source={require('../assets/hee.png')} /> </View> <View style={styles.box2}> <TextInput label="Email" value={email} onChangeText={(text)=>setEmail(text)} mode="outlined" /> <TextInput label="password" mode="outlined" value={password} onChangeText={(text)=>setPassword(text)} secureTextEntry /> <TextInput label="Full Name" value={name} onChangeText={(text)=>setName(text)} mode="outlined" /> <Button mode="contained" style={{marginTop:20}} onPress={()=>userSignup()} >Signup</Button> <TouchableOpacity onPress={()=>navigation.goBack()}><Text style={{textAlign:"center", marginTop:25}}>Already have an account ?</Text></TouchableOpacity> </View> </KeyboardAvoidingView> </ScrollView> ) } export default SignupScreen const styles = StyleSheet.create({ text:{ fontSize:22, color:"green", margin:15 }, img:{ width:250, height:250 }, box1:{ alignItems:"center" }, box2:{ width:"70%", justifyContent:"center", height:"50%", margin:20, marginLeft:55 } });
2. 修正Main页面代码
增加状态存储选中的用户类型,补全输入框渲染,修正按钮逻辑,跳转注册页时传递type参数:
import React,{useState} from 'react' import { View, Text ,Image,StyleSheet,KeyboardAvoidingView,TouchableOpacity,ActivityIndicator} from 'react-native' import { TextInput,Button } from 'react-native-paper'; import auth from '@react-native-firebase/auth' const Main =props=> { const [email,setEmail] = useState('') const [password,setPassword] = useState('') const [loading,setLoading] = useState(false) // 新增状态存储当前选中的用户类型,默认普通用户 const [selectedType,setSelectedType] = useState('User') if(loading){ return <ActivityIndicator size="large" color="red" /> } const userLogin = async ()=>{ setLoading(true) if(!email || !password){ alert("please add all the field") setLoading(false) return } try{ const result = await auth().signInWithEmailAndPassword(email,password) // 登录后可查询用户表中存储的type字段,跳转到对应身份的首页 setLoading(false) }catch(err){ setLoading(false) alert("something went wrong") } } return ( <KeyboardAvoidingView behavior="position"> <View style={styles.box1}> <Image style={styles.img} source={require('../assets/hee.png')} /> </View> <View style={styles.box2}> <TextInput label="Email" value={email} onChangeText={(text)=>setEmail(text)} mode="outlined" /> <TextInput label="password" mode="outlined" value={password} onChangeText={(text)=>setPassword(text)} secureTextEntry /> <Button mode="contained" onPress={()=>{ setSelectedType('Doctor') userLogin() }} >Doctor</Button> <Button mode="contained" onPress={()=>{ setSelectedType('User') userLogin() }} >User</Button> <TouchableOpacity // 跳转时传递选中的用户类型 onPress={()=>props.navigation.navigate('signup',{type: selectedType})}> <Text style={{textAlign:"center"}}>Dont have an account ?</Text> </TouchableOpacity> </View> </KeyboardAvoidingView> ) } export default Main const styles = StyleSheet.create({ text:{ fontSize:22, color:"red", margin:10 }, img:{ width:250, height:250 }, box1:{ alignItems:"center" }, box2:{ paddingHorizontal:40, justifyContent:"space-evenly", height:"50%" } });
不依赖页面props传参的替代方案
- 全局状态管理:使用React Context、Zustand、Redux等全局状态方案,在Main页面选中用户类型后存入全局store,SignUpScreen直接从全局store读取身份值,完全不需要依赖路由传参,适合多页面共享身份状态的场景。
- 本地缓存存储:选中用户类型后通过
@react-native-async-storage/async-storage将类型值存在本地,SignUpScreen渲染时直接读取本地缓存的类型,就算应用重启、深链进入页面也不会丢失参数。 - 多路由配置:给医生、普通用户的注册页配置两个独立的路由名(如
DoctorSignup、UserSignup),两个路由可指向同一个SignUpScreen组件,跳转时直接跳对应路由即可,不需要额外传参,路由语义更清晰。 - 导航封装校验:封装统一的导航跳转工具函数,强制要求跳转到SignUpScreen时必须传入type参数,结合TypeScript类型校验可以从根源上避免漏传参数的问题。
内容的提问来源于stack exchange,提问作者dbafix
相关产品推荐
相关产品推荐

