如何修复Expo React Native应用中的‘Element type is invalid’错误
跟随Expo官方图片选择器教程开发应用时,反复遇到「Element type is invalid」错误,即使从头搭建项目、完全复制教程代码仍无法解决,注释App.js顶部导入语句也没用。
完整错误信息
Error: Element type is invalid: expected a string (for built-in components) or a class/function (for composite components) but got: object. You likely forgot to export your component from the file it's defined in, or you might have mixed up default and named imports.
错误定位:App组件的渲染方法中,具体调用栈如下:
in RCTView (created by View)
in View (created by App)
in RCTView (created by View)
in View (created by App)
in App (created by withDevTools(App))
in withDevTools(App)
in RCTView (created by View)
in View (created by AppContainer)
in RCTView (created by View)
in View (created by AppContainer)
in AppContainer
in main(RootComponent), js engine: hermes
代码示例
App.js
import { StatusBar } from 'expo-status-bar'; import { StyleSheet, View, Image } from 'react-native'; import Button from './components/Button'; import ImageViewer from './components/ImageViewer'; import * as ImagePicker from 'expo-image-picker'; import { useState } from 'react'; const PlaceholderImage = require('./assets/images/background-image.png'); export default function App() { const [selectedImage, setSelectedImage] = useState(null); const pickImageAsync = async () => { let result = await ImagePicker.launchImageLibraryAsync({ allowsEditing: true, quality: 1, }); if (!result.canceled) { setSelectedImage(result.assets[0].uri); } else { alert('You did not select any image.'); } }; return ( <View style={styles.container}> <View style={styles.imageContainer}> <ImageViewer placeholderImageSource={PlaceholderImage} selectedImage={selectedImage} /> </View> <View style={styles.footerContainer}> <Button theme="primary" label="Choose a photo" onPress={pickImageAsync} /> <Button label="Use this photo" /> </View> <StatusBar style="auto" /> </View> ); } const styles = StyleSheet.create({ container: { flex: 1, backgroundColor: '#25292e', alignItems: 'center', }, imageContainer: { flex: 1, paddingTop: 58, }, image: { width: 320, height: 440, borderRadius: 18, }, footerContainer: { flex: 1 / 3, alignItems: 'center', }, });
Button.js
import { StyleSheet, View, Pressable, Text } from 'react-native'; import FontAwesome from '@expo/vector-icons/FontAwesome'; export default function Button({ label, theme, onPress }) { if (theme === 'primary') { return ( <View style={[styles.buttonContainer, {borderWidth: 4, borderColor: "#ffd33d", borderRadius: 18 }]} > <Pressable style={[styles.button, { backgroundColor: "#fff" }]} onPress={onPress} > <FontAwesome name="picture-o" size={18} color="#25292e" style={styles.buttonIcon} /> <Text style={[styles.buttonLabel, { color: "#25292e" }]}>{label}</Text> </Pressable> </View> ); } return ( <View style={StyleSheet.buttonContainer}> <Pressable style={styles.button} onPress={() => alert('You pressed a button.')}> <Text style={styles.buttonLabel}>{label}</Text> </Pressable> </View> ); } const styles = StyleSheet.create({ buttonContainer: { width: 320, height: 68, marginHorizontal: 20, alignItems: 'center', padding: 3, }, button: { borderRadius: 10, width: '100%', height: '100%', alignItems: 'center', justifyContent: 'center', flexDirection: 'row', }, buttonIcon: { paddingRight: 8, }, buttonLabel: { color: '#fff', fontSize: 16, }, });
ImageViewer.js
import { StyleSheet, Image } from 'react-native'; export default function ImageViewer({ placeholderImageSource, selectedImage }) { const imageSource = selectedImage !== null ? { uri: selectedImage } : placeholderImageSource; return <Image source={imageSource} style={styles.image} />; } const styles = StyleSheet.create({ image: { width: 320, height: 440, borderRadius: 18, }, });
问题原因与解决方法
- 问题根源:
Button.js的非primary分支代码中,View组件的style属性错误引用了StyleSheet.buttonContainer——StyleSheet是React Native的内置类,本身没有buttonContainer属性,这个引用会返回undefined,导致React无法识别有效的样式对象,进而触发「Element type is invalid」错误。 - 修复方案:将
StyleSheet.buttonContainer改为styles.buttonContainer(styles是你通过StyleSheet.create创建的本地样式对象)。
修正后的Button.js对应代码片段:
return ( <View style={styles.buttonContainer}> <Pressable style={styles.button} onPress={() => alert('You pressed a button.')}> <Text style={styles.buttonLabel}>{label}</Text> </Pressable> </View> );
内容的提问来源于stack exchange,提问作者EntrepreneurTim

