Android Studio模拟器中React Native应用启动即崩溃,求原因排查
问题描述
我正在重构组件以访问Firebase托管的其他数据,但应用在Android Studio模拟器中一启动就崩溃了,抛出的错误信息如下:
FATAL EXCEPTION: main Process: com.auth, PID: 3320 com.facebook.react.uimanager.IllegalViewOperationException: Trying to add unknown view tag: 5 detail: View tag:21 children(1): [ 4, ], viewsToAdd(1): [ [1,5], ]
我使用的代码如下:
import React, { Component } from 'react'; import { View } from 'react-native'; import axios from 'axios'; import firebase from 'firebase'; import { Header, Button, Spinner, CardSection, AlbumDetail } from './components/common'; import LoginForm from './components/LoginForm'; class App extends Component { state = { loggedIn: null, albums: [] }; componentWillMount() { firebase.initializeApp({ apiKey: 'xx', authDomain: 'xx', databaseURL: 'xx', projectId: 'xx', storageBucket: 'xx', messagingSenderId: 'xx' }); axios.get('https://xx') .then(response => this.setState({ albums: response.data })); firebase.auth().onAuthStateChanged((user) => { if (user) { this.setState({ loggedIn: true }); } else { this.setState({ loggedIn: false }); } }); } renderAlbums() { return this.state.albums.map(album => <AlbumDetail key={album.District} album={album} />); } renderContent() { switch (this.state.loggedIn) { case true: return ( <CardSection> <Button onPress={() => firebase.auth().signOut()}> Log Out </Button> </CardSection> ); case false: return <LoginForm />; default: return <Spinner size='large' />; } } render() { return ( <View> <Header headerText='Authentication' /> console.log(this.state.albums) {this.renderContent()} </View> ); } } export default App;
请问可能是什么原因导致的?
问题原因与解决方案
嘿,我一眼就揪出你代码里的问题了——在render方法的JSX结构里,你直接裸写了console.log(this.state.albums),这完全不符合React Native的JSX语法规则!
JSX要求组件内部的所有内容必须是合法的React元素或者被大括号包裹的表达式,而你把日志语句直接放在<View>里,React Native会误以为这是一个要渲染的视图组件,结果发现它根本不是有效的视图标签,自然就抛出了IllegalViewOperationException崩溃错误。
修复步骤超简单:
- 最规范的做法是把
console.log移到render方法的开头,在返回JSX结构之前执行:
render() { console.log(this.state.albums); // 移到这里就对了 return ( <View> <Header headerText='Authentication' /> {this.renderContent()} </View> ); }
- 如果你非要在JSX里插入日志,也得把它放在大括号里(不过这种写法不推荐,因为每次组件渲染都会触发,控制台可能会被刷屏):
render() { return ( <View> <Header headerText='Authentication' /> {console.log(this.state.albums)} {this.renderContent()} </View> ); }
另外提个小优化点:componentWillMount在React新版本里已经被标记为过时API了,推荐换成componentDidMount(类组件)或者useEffect(函数组件),不过这不是导致本次崩溃的直接原因,只是个长期维护的建议。
改完代码后重新运行模拟器,应该就能正常启动啦!
内容的提问来源于stack exchange,提问作者Karthigeyan Kalyan

