You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React Native Invalid hook call错误排查及代码修复请求

React Native错误排查与修复方案

核心错误原因

你遇到的Invalid hook call、TypeError: null is not an object (evaluating 'dispatcher.useState')错误,根源是违反了Hooks使用规则:

  • 你将useState Hook定义在了类组件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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.18 11:26:11