React Native中SelectList下拉框触发Invalid hook call错误求助
问题根源
- Invalid hook call错误:你的
AddUsersScreen是类组件(继承自Component),但在constructor里使用了React.useState——Hooks只能在函数组件或自定义Hook的顶层作用域调用,类组件完全不支持Hooks,这直接违反了Hook规则。 - ReferenceError: setSelected找不到:你在
constructor里声明的[selected, setSelected]是局部变量,render函数无法访问该变量,调用时自然会报错。
修复方案(类组件适配,改动最小)
直接用类组件的this.state管理下拉选中值,完全不需要Hooks:
- 在类的
state中添加选中状态字段; - 修改
SelectList的setSelected回调为this.setState更新选中值; - 修正注册逻辑中
householdId的赋值,确保选中的家庭ID能存入数据库; - 修复输入框的value绑定笔误,避免输入内容不回显。
修改后的完整代码:
// components/AddUsersScreen.js import { Component } from 'react'; import * as React from 'react'; import { StyleSheet, Text, View, TextInput, Alert, ActivityIndicator } from 'react-native'; import firebase from '../database/firebaseDb'; //css import { styles } from "../css/Styles"; // import CheckBox from '@react-native-community/checkbox' import SelectDropdown from 'react-native-select-dropdown' import { SelectList } from 'react-native-dropdown-select-list' export default class AddUsersScreen extends Component { constructor() { super(); this.dbRef = firebase.firestore().collection('users'); this.firestoreRef = firebase.firestore().collection('household'); this.state = { displayName : '', lastname: '', email: '', phoneNumber: '', password:'', householdId : '', active : '', uid: '', roleId : '', selected: '' // 新增:存储下拉选中的家庭ID } // 移除此处的useState调用,类组件禁止使用Hooks } componentDidMount(){ this.unsubscribe = this.firestoreRef.onSnapshot(this.getCollection); } componentWillUnmount(){ this.unsubscribe(); } getCollection = (querySnapshot) => { const householdArr = []; querySnapshot.forEach((res) => { const {householdName} = res.data(); householdArr.push({ householdId: res.id, householdName }); }); this.setState({ householdArr, isLoading: false, }); const householdOptions = householdArr.map(d => ({ "key" : d.householdId, "value" : d.householdName })) this.setState({selectOptions: householdOptions}) } updateInputVal = (val, prop) => { const state = this.state; state[prop] = val; this.setState(state); } storeUser = () => { this.setState({ isLoading: true, }); this.dbRef.doc(this.userDetails.uid).set({ displayName : this.userDetails.displayName, lastname: this.userDetails.lastname, email:this.userDetails.email, phoneNumber: this.userDetails.phoneNumber, householdId : this.userDetails.householdId, roleId : this.userDetails.roleId, active : this.userDetails.active, uid: this.userDetails.uid }).then((res) => { this.setState({ isLoading: false, displayName : '', lastname: '', email: '', phoneNumber: '', password:'', householdId : '', roleId : '', active : '', uid: '', selected: '' // 重置选中状态 }); console.log("added") }) .catch((err) => { console.error("Error found: ", err); this.setState({ isLoading: false, }); }); } registerUser = () => { if(this.state.email === '' || this.state.password === '' || this.state.displayName === '' || this.state.phoneNumber === '') { Alert.alert('Enter all details!') return; } if(this.state.password.length < 6){ Alert.alert('Password should be more than 6 characters!') return; } if(!this.state.selected) { Alert.alert('Please select a household!') return; } this.setState({ isLoading: true }) firebase .auth() .createUserWithEmailAndPassword(this.state.email, this.state.password) .then((res) => { res.user.updateProfile({ displayName: this.state.displayName, phoneNumber: this.state.phoneNumber }) console.log('User registered successfully! UID : ' + res.user.uid) this.userDetails = { displayName : this.state.displayName, lastname: this.state.lastname, email:this.state.email, phoneNumber: this.state.phoneNumber, householdId : this.state.selected, // 绑定选中的家庭ID roleId : 2, active : 1, uid: res.user.uid } this.storeUser(); this.setState({ isLoading: false, displayName : '', lastname: '', email: '', password:'', phoneNumber: '', householdId : '', roleId : '', active : '', uid: '', selected: '' }) }) .catch(error => this.setState({ errorMessage: error.message })) } render() { if(this.state.isLoading){ return( <View style={styles.preloader}> <ActivityIndicator size="large" color="#d00"/> </View> ) } return ( <View style={styles.container}> <TextInput style={styles.inputStyle} placeholder="First Name" value={this.state.displayName} onChangeText={(val) => this.updateInputVal(val, 'displayName')} /> <TextInput style={styles.inputStyle} placeholder="Last Name" value={this.state.lastname} onChangeText={(val) => this.updateInputVal(val, 'lastname')} /> <TextInput style={styles.inputStyle} placeholder="Email" value={this.state.email} onChangeText={(val) => this.updateInputVal(val, 'email')} /> <TextInput style={styles.inputStyle} placeholder="Phone Number" value={this.state.phoneNumber} // 修复笔误:从mobile改为phoneNumber onChangeText={(val) => this.updateInputVal(val, 'phoneNumber')} maxLength={15} /> <TextInput style={styles.inputStyle} placeholder="Password" value={this.state.password} onChangeText={(val) => this.updateInputVal(val, 'password')} maxLength={15} secureTextEntry={true} /> <SelectList placeholder='Select Household' setSelected={(val) => this.setState({ selected: val })} // 用this.setState更新选中值 data={this.state.selectOptions} save="key" search={false} defaultValue={this.state.selected} /> <View style={styles.buttonsContainer}> <Text style={styles.buttons} onPress={() => this.registerUser()}>Add User</Text> <Text style={styles.buttons} onPress={() => this.props.navigation.navigate('UserListsScreen')}>Back to Users List</Text> </View> </View> ); } }
额外说明
如果想迁移到React现代写法,也可以将类组件改为函数组件,用useState管理状态、useEffect替代生命周期方法,这样就能合法使用Hooks,但整体改动会更大。
内容的提问来源于stack exchange,提问作者blueazulbughaw
相关产品推荐
相关产品推荐

