React Native Invalid hook call错误排查及代码修复请求
React Native错误排查与修复方案
核心错误原因
你遇到的Invalid hook call、TypeError: null is not an object (evaluating 'dispatcher.useState')错误,根源是违反了Hooks使用规则:
- 你将
useStateHook定义在了类组件App的外部,而Hooks只能在函数组件的顶层或自定义Hook内部调用。
另外,Invariant Violation: "main"未注册错误,大概率是Metro服务器运行目录错误,或是组件注册异常,后续会附带排查建议。
修复方案
方案1:将类组件改为函数组件(推荐,符合React新特性)
把类组件改写为函数组件,统一使用Hooks管理状态,移除类组件的constructor和setState写法:
import * as React from 'react'; import { useState } from 'react'; import { Text, StyleSheet, KeyboardAvoidingView, ScrollView, Image, TextInput, TouchableOpacity, View } from 'react-native'; import { CheckBox } from 'react-native-elements'; import { Ionicons } from '@expo/vector-icons' export default function App() { // 将状态移到函数组件内部 const [input, setInput] = useState(''); const [hidePass, setHidePass] = useState(true); const [ischecked1, setIschecked1] = useState(true); const onChangeCheck1 = () => { setIschecked1(!ischecked1); } return ( <KeyboardAvoidingView style={styles.container}> <ScrollView> <Image source={require('./assets/logo.png')} style={styles.logo} /> <Text style={styles.helloText}> Olá de novo ! </Text> <Text style={styles.welcomeText}> Bem-vindo(a) de volta, sentimos sua falta! </Text> <TextInput style={styles.inputArea} placeholder="Digite o e-mail" /> <TextInput style={styles.inputArea} placeholder="Senha" value={input} onChangeText={(texto) => setInput(texto)} secureTextEntry={hidePass} /> <TouchableOpacity style={styles.eye} onPress={() => setHidePass(!hidePass)}> <Ionicons name={hidePass ? 'eye' : 'eye-off'} color="#A0D800" size={25} /> </TouchableOpacity> <View style={styles.checkBoxStyle}> <CheckBox left size={18} checkedColor='#A0D800' value={ischecked1} checked={ischecked1} onPress={onChangeCheck1} containerStyle={{ backgroundColor: "transparent", borderColor: "transparent", marginRight: 0 }} /> <Text style={styles.Connected}> Manter-se conectado </Text> <Text style={styles.forgotPassword}> Esqueci minha senha </Text> </View> <TouchableOpacity style={styles.botao} > <Text style={styles.botaoText}>Entrar</Text> </TouchableOpacity> </ScrollView> </KeyboardAvoidingView> ); } const styles = StyleSheet.create({ container: { flex: 2, justifyContent: 'center', alignItems: 'center', backgroundColor: '#fff' }, logo: { marginTop: 50, marginBottom: 80, width: 150, height: 40, }, inputArea: { marginTop: 30, padding: 15, height: 60, width: 370, borderColor: '#808080', borderWidth: 1, backgroundColor: '#fff', fontSize: 16, fontWeight: 'bold', borderRadius: 15 }, botao: { width: 350, height: 60, backgroundColor: '#000000', marginTop: 50, marginLeft: 8, borderRadius: 15, alignItems: 'center', justifyContent: 'center' }, botaoText: { fontSize: 15, fontWeight: 'bold', color: '#fff' }, helloText: { fontSize: 40, fontWeight: 'bold', marginTop: 8, color: '#000000', marginEnd: 120, }, welcomeText: { fontSize: 16, marginTop: 10, marginEnd: 35, marginVertical: 10, color: '#808080', }, forgotPassword: { textDecorationLine: 'underline', fontWeight: 'bold', marginTop: 15, marginBottom: 15, marginLeft: 30, fontSize: 12 }, Connected: { textDecorationLine: 'underline', fontWeight: 'bold', marginTop: 15, fontSize: 12, marginRight: 55, marginLeft: -5 }, checkBoxStyle: { marginTop: 15, flexDirection: 'row', marginStart: -10 }, eye: { alignSelf: 'flex-end', bottom: 42, right: 40 } })
方案2:保留类组件,移除Hooks改用类组件状态管理
如果坚持使用类组件,需要把useState定义的状态移到类的state中,用setState更新:
import * as React from 'react'; import { Text, StyleSheet, KeyboardAvoidingView, ScrollView, Image, TextInput, TouchableOpacity, View } from 'react-native'; import { CheckBox } from 'react-native-elements'; import { Ionicons } from '@expo/vector-icons' export default class App extends React.Component { constructor(props) { super(props); this.state = { ischecked1: true, input: '', // 新增input状态 hidePass: true // 新增hidePass状态 }; } onChangeCheck1() { this.setState({ ischecked1: !this.state.ischecked1 }); } render() { const { input, hidePass } = this.state; return ( <KeyboardAvoidingView style={styles.container}> <ScrollView> <Image source={require('./assets/logo.png')} style={styles.logo} /> <Text style={styles.helloText}> Olá de novo ! </Text> <Text style={styles.welcomeText}> Bem-vindo(a) de volta, sentimos sua falta! </Text> <TextInput style={styles.inputArea} placeholder="Digite o e-mail" /> <TextInput style={styles.inputArea} placeholder="Senha" value={input} onChangeText={(texto) => this.setState({ input: texto })} secureTextEntry={hidePass} /> <TouchableOpacity style={styles.eye} onPress={() => this.setState({ hidePass: !hidePass })}> <Ionicons name={hidePass ? 'eye' : 'eye-off'} color="#A0D800" size={25} /> </TouchableOpacity> <View style={styles.checkBoxStyle}> <CheckBox left size={18} checkedColor='#A0D800' value={this.state.ischecked1} checked={this.state.ischecked1} onPress={this.onChangeCheck1.bind(this)} containerStyle={{ backgroundColor: "transparent", borderColor: "transparent", marginRight: 0 }} /> <Text style={styles.Connected}> Manter-se conectado </Text> <Text style={styles.forgotPassword}> Esqueci minha senha </Text> </View> <TouchableOpacity style={styles.botao} > <Text style={styles.botaoText}>Entrar</Text> </TouchableOpacity> </ScrollView> </KeyboardAvoidingView> ); } } // 样式部分保持不变 const styles = StyleSheet.create({ container: { flex: 2, justifyContent: 'center', alignItems: 'center', backgroundColor: '#fff' }, logo: { marginTop:50, marginBottom: 80, width: 150, height: 40, }, inputArea:{ marginTop: 30, padding: 15, height: 60, width: 370, borderColor: '#808080', borderWidth: 1, backgroundColor: '#fff', fontSize: 16, fontWeight: 'bold', borderRadius: 15 }, botao: { width: 350, height: 60, backgroundColor: '#000000', marginTop: 50, marginLeft: 8, borderRadius: 15, alignItems: 'center', justifyContent: 'center' }, botaoText: { fontSize: 15, fontWeight: 'bold', color: '#fff' }, helloText: { fontSize: 40, fontWeight: 'bold', marginTop: 8, color: '#000000', marginEnd: 120, }, welcomeText: { fontSize: 16, marginTop: 10, marginEnd: 35, marginVertical: 10, color: '#808080', }, forgotPassword: { textDecorationLine: 'underline', fontWeight: 'bold', marginTop: 15, marginBottom: 15, marginLeft: 30, fontSize: 12 }, Connected:{ textDecorationLine: 'underline', fontWeight: 'bold', marginTop: 15, fontSize: 12, marginRight: 55, marginLeft: -5 }, checkBoxStyle:{ marginTop: 15, flexDirection: 'row', marginStart: -10 }, eye:{ alignSelf: 'flex-end', bottom: 42, right: 40 } })
"main"未注册错误排查
- 确保Metro开发服务器在项目根目录启动,若当前目录不对,关闭服务器后回到项目根目录重新运行
npx expo start或react-native start - 确认App组件已通过
export default正确导出,Expo或React Native会自动完成AppRegistry.registerComponent注册,无需手动添加
内容的提问来源于stack exchange,提问作者Ann37
相关产品推荐
相关产品推荐

