React Native电影搜索App报错:Cannot read property 'map' of undefined
问题分析与解决
核心问题
- 初始状态类型不匹配:你把
movies的初始状态设为数组[],但fetchMovies返回的是包含Search数组的对象(比如{ Search: [...] })。组件首次渲染时,movies是数组,movies.Search自然为undefined,直接调用map就会触发报错。 - 未处理数据加载前的空值:即便修正初始状态,API请求完成前
movies.Search仍可能是undefined,直接调用map会引发错误。
修复步骤
1. 修正初始状态类型
将movies的初始状态改为空对象,匹配API返回的数据结构:
const [movies, setMovies] = useState({});
2. 安全调用map方法
在调用map前,先判断movies.Search是否存在,或使用可选链操作符(?.)避免空值报错:
{ movies.Search?.map((movie,i)=>( <MovieCard movie={movie} key={i}/> )) }
也可以用更严谨的判断逻辑:
{ movies.Search && Array.isArray(movies.Search) && movies.Search.map((movie,i)=>( <MovieCard movie={movie} key={i}/> )) }
3. 调整Header显示逻辑(可选)
原代码中Object.keys(movies).length > 0的判断会导致初始状态下Header不显示,若想一开始就展示搜索栏,可直接去掉该判断:
<View style={styles.Header}> <TextInput style={styles.SearchBar} placeholder='Search...' value={searchMovie} onChangeText={(text)=>setSearchMovie(text)} left = {<TextInput.Icon name='magnify'/>} onPress={Search} onSubmitEditing={Search}/> <Button title="Search" onPress={() => navigation.navigate('Info')} /> </View>
完整修改后的代码
import React, { useEffect, useState } from 'react'; import {StyleSheet,View,Button,ScrollView} from 'react-native'; import {TextInput} from 'react-native-paper'; import { fetchMovies } from '../API/Index'; import {MovieCard} from './MovieCard'; function SearchScreen({navigation}) { // 修正初始状态为对象 const [movies, setMovies] = useState({}); console.log(movies); const [searchMovie, setSearchMovie] = useState('Harry Potter'); useEffect(()=>{ const getMovies = async() =>setMovies(await fetchMovies(searchMovie)) getMovies(); },[]) const Search = async () => { setMovies(await fetchMovies(searchMovie)); setSearchMovie(''); }; return ( <View style={styles.Container}> {/* 去掉判断,始终显示Header */} <View style={styles.Header}> <TextInput style={styles.SearchBar} placeholder='Search...' value={searchMovie} onChangeText={(text)=>setSearchMovie(text)} left = {<TextInput.Icon name='magnify'/>} onPress={Search} onSubmitEditing={Search}/> <Button title="Search" onPress={() => navigation.navigate('Info')} /> </View> <ScrollView contentContainerStyle={{ flexDirection: 'row', flexWrap: 'wrap', justifyContent: 'space-around', alignItems: 'center' }}> {/* 使用可选链安全调用map */} { movies.Search?.map((movie,i)=>( <MovieCard movie={movie} key={i}/> )) } </ScrollView> </View> ); } const styles = StyleSheet.create({ Container:{ flex: 1, alignItems: 'center', justifyContent: 'center' }, Header:{ flexDirection: 'row', backgroundColor:'#000000', alignItems: "center", justifyContent: 'center', width:'100%' }, SearchBar:{ borderColor: "#FFFFFF", backgroundColor: "#DDDDDD", marginHorizontal: 5 }, }); export default SearchScreen;
内容的提问来源于stack exchange,提问作者Ignis
相关产品推荐
相关产品推荐

