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

使用Expo Go启动React Native应用时出现导航对象缺失渲染错误

修复“找不到导航对象”错误并实现Microsoft账户双因素登录

我正在实现基于Microsoft Account搭配Microsoft Authenticator的双因素登录功能,但测试时遇到以下错误:

Render Error. Couldn't find a navigation object. Is your component inside NavigationContainer?

我试过两段代码但都无效,代码如下:

尝试的第一段代码(类组件)

import React, { Component } from 'react';
import { View, Button, Text } from 'react-native';
import { UserAgentApplication } from 'react-native-msal';
import { AuthenticationParameters } from 'react-native-msal';

export default class Login extends Component {
  constructor(props) {
    super(props);

    this.auth = new UserAgentApplication({
      auth: {
        clientId: 'My_Client_ID',
        authority: 'My_Authority',
        redirectUri: 'exp://85-nny.anonymous.donewithit.exp.direct:80/--/auth', // 不确定这个重定向URL是否有效
      },
    });

    this.state = {
      accessToken: null,
      userInfo: null,
    };
  }

  login = async () => {
    try {
      const authResult = await this.auth.login();
      const accessToken = authResult.accessToken;

      if (accessToken) {
        this.setState({ accessToken });
        this.getUserInfo();
      }
    } catch (error) {
      console.error(error);
    }
  }

  getUserInfo = async () => {
    try {
      const authParameters = new AuthenticationParameters();
      authParameters.scopes = ['openid', 'profile'];

      const userInfo = await this.auth.acquireTokenSilent(authParameters);
      this.setState({ userInfo });
    } catch (error) {
      console.error(error);
    }
  }

  logout = () => {
    this.auth.logout();
    this.setState({ accessToken: null, userInfo: null });
  }

  render() {
    const { accessToken, userInfo } = this.state;

    return (
      <View>
        {accessToken ? (
          <Button title="Logout" onPress={this.logout} />
        ) : (
          <Button title="Login with Microsoft" onPress={this.login} />
        )}

        {userInfo && (
          <View>
            <Text>Welcome, {userInfo.displayName}</Text>
            <Text>Email: {userInfo.userPrincipalName}</Text>
          </View>
        )}
      </View>
    );
  }
}

export default Login;

尝试的第二段代码(函数式组件)

import React from 'react';
import { View, Text, Button } from 'react-native';
import { authorize } from 'react-native-app-auth';
import { useNavigation } from '@react-navigation/native';

const Login = () => {
  const navigation = useNavigation();

  const config = {
    clientId: 'My_Client_ID',
    redirectUrl: 'exp://85-nny.anonymous.donewithit.exp.direct:80/--/auth',
    scopes: ['openid', 'profile', 'email', 'offline_access', 'User.Read'],
    serviceConfiguration: {
      authorizationEndpoint: 'https://login.microsoftonline.com/common/oauth2/v2.0/authorize',
      tokenEndpoint: 'https://login.microsoftonline.com/common/oauth2/v2.0/token',
    },
  };

  const loginWithMicrosoft = async () => {
    try {
      const result = await authorize(config);

      // 用户登录成功后跳转到首页
      if (result.idToken) {
        navigation.navigate('HomeScreen');
      }
    } catch (error) {
      console.error('Authentication Error:', error);
    }
  };

  return (
    <View>
      <Text>Login Page</Text>
      <Button title="Login with Microsoft" onPress={loginWithMicrosoft} />
    </View>
  );
};

export default Login;

错误原因与修复方案

这个错误的核心是Login组件没有被嵌套在React Navigation的NavigationContainer内部,或者类组件没有正确获取导航实例。

1. 先配置根组件的NavigationContainer

确保App入口文件用NavigationContainer包裹整个导航结构,这是React Navigation的强制要求:

import { NavigationContainer } from '@react-navigation/native';
import { createStackNavigator } from '@react-navigation/stack';
import Login from './Login';
import HomeScreen from './HomeScreen';

const Stack = createStackNavigator();

export default function App() {
  return (
    <NavigationContainer>
      <Stack.Navigator initialRouteName="Login">
        <Stack.Screen name="Login" component={Login} />
        <Stack.Screen name="HomeScreen" component={HomeScreen} />
      </Stack.Navigator>
    </NavigationContainer>
  );
}

2. 修复函数式组件的导航逻辑

确保useNavigation在NavigationContainer的子组件中使用,同时优化双因素认证触发逻辑:

import React from 'react';
import { View, Text, Button, StyleSheet } from 'react-native';
import { authorize } from 'react-native-app-auth';
import { useNavigation } from '@react-navigation/native';

const Login = () => {
  const navigation = useNavigation();

  const config = {
    clientId: 'My_Client_ID',
    redirectUrl: 'exp://85-nny.anonymous.donewithit.exp.direct:80/--/auth',
    scopes: ['openid', 'profile', 'email', 'offline_access', 'User.Read'],
    serviceConfiguration: {
      authorizationEndpoint: 'https://login.microsoftonline.com/common/oauth2/v2.0/authorize',
      tokenEndpoint: 'https://login.microsoftonline.com/common/oauth2/v2.0/token',
    },
    // 强制触发双因素认证流程
    additionalParameters: {
      prompt: 'select_account',
    },
  };

  const loginWithMicrosoft = async () => {
    try {
      const result = await authorize(config);
      if (result.idToken) {
        navigation.navigate('HomeScreen');
      }
    } catch (error) {
      console.error('认证错误:', error);
    }
  };

  return (
    <View style={styles.container}>
      <Text>登录页面</Text>
      <Button title="使用Microsoft账户登录" onPress={loginWithMicrosoft} />
    </View>
  );
};

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
  },
});

export default Login;

3. 修复类组件的导航逻辑

类组件需要通过withNavigation高阶组件包裹来获取导航props,同时补充双因素触发参数:

import React, { Component } from 'react';
import { View, Button, Text, StyleSheet } from 'react-native';
import { UserAgentApplication } from 'react-native-msal';
import { AuthenticationParameters } from 'react-native-msal';
import { withNavigation } from '@react-navigation/compat';

class Login extends Component {
  constructor(props) {
    super(props);

    this.auth = new UserAgentApplication({
      auth: {
        clientId: 'My_Client_ID',
        authority: 'My_Authority',
        redirectUri: 'exp://85-nny.anonymous.donewithit.exp.direct:80/--/auth',
      },
    });

    this.state = {
      accessToken: null,
      userInfo: null,
    };
  }

  login = async () => {
    try {
      const authResult = await this.auth.login({
        scopes: ['openid', 'profile', 'email'],
        prompt: 'select_account', // 触发双因素认证
      });
      const accessToken = authResult.accessToken;

      if (accessToken) {
        this.setState({ accessToken });
        this.getUserInfo();
        this.props.navigation.navigate('HomeScreen');
      }
    } catch (error) {
      console.error(error);
    }
  }

  getUserInfo = async () => {
    try {
      const authParameters = new AuthenticationParameters();
      authParameters.scopes = ['openid', 'profile'];

      const userInfo = await this.auth.acquireTokenSilent(authParameters);
      this.setState({ userInfo });
    } catch (error) {
      console.error(error);
    }
  }

  logout = () => {
    this.auth.logout();
    this.setState({ accessToken: null, userInfo: null });
    this.props.navigation.navigate('Login');
  }

  render() {
    const { accessToken, userInfo } = this.state;

    return (
      <View style={styles.container}>
        {accessToken ? (
          <Button title="退出登录" onPress={this.logout} />
        ) : (
          <Button title="使用Microsoft账户登录" onPress={this.login} />
        )}

        {userInfo && (
          <View style={styles.userInfo}>
            <Text>欢迎, {userInfo.displayName}</Text>
            <Text>邮箱: {userInfo.userPrincipalName}</Text>
          </View>
        )}
      </View>
    );
  }
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
  },
  userInfo: {
    marginTop: 20,
    alignItems: 'center',
  },
});

// 用withNavigation包裹以获取导航props
export default withNavigation(Login);

额外注意事项

  • 重定向URL有效性:当前使用的Expo开发URL仅适用于调试,正式发布时需要在Azure Portal的应用注册中配置对应平台的URI(iOS为msauth://{BundleId}/{Base64编码的重定向URI},Android为msauth://{PackageName}/{Base64编码的重定向URI})。
  • 双因素认证触发:通过添加prompt: 'select_account'参数,确保Microsoft身份验证服务强制触发双因素认证流程。

内容的提问来源于stack exchange,提问作者Kim

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.07 23:28:10