React Native - 渲染从 API 获取数据的屏幕时出现“未定义不是对象”错误

Posted

技术标签:

【中文标题】React Native - 渲染从 API 获取数据的屏幕时出现“未定义不是对象”错误【英文标题】:React Native - "Undefined is not an object" error when render a screen that take data from API 【发布时间】:2021-09-15 22:33:57 【问题描述】:

我是 React Native 的新手。我正在制作一个从 API 获取数据并将其显示在屏幕上的应用程序。呈现此屏幕时会出现以下错误: 渲染错误 undefined 不是对象(评估 'character.origin.name')

屏幕上的代码:

const CharacterDetailScreen = (props) => 

    const  styles, colors  = useThemedValues(getStyles);
    const loc = useLocalization();

    **// state for character detail**
    const [character, setCharacter] = useState([])

    **// this id come from previous screen**
    const  characterId  = props.route.params

    useEffect(()=>
        Axios.get('character/'+characterId)
            .then(response =>
                characterDetail = response.data
                setCharacter(characterDetail)
                console.log(characterDetail.name) // if characterId=89, writes "dale" in console
            )
            .catch(error => 
                console.log(error)
            )
    ,[])
 
    return (
        <View style=styles.container>
            <View style=styles.imageContainer>
                <Image source= uri: character.image 
                    style=styles.image
                />
            </View>
            <View style=styles.characterNameContainer>
                <Text style=styles.characterName>character.name</Text>
            </View>
            <View style=styles.detailContainer>
                <Text style=styles.detailText >loc.t(texts.status)character.status</Text>
                <Text style=styles.detailText >loc.t(texts.species)character.species</Text>
                <Text style=styles.detailText >loc.t(texts.gender)character.gender</Text>
                <Text style=styles.detailText >loc.t(texts.type)character.type</Text>
                <Text style=styles.detailText >loc.t(texts.origin)character.origin.name</Text>
                <Text style=styles.detailText >loc.t(texts.location)character.location.name</Text>
            </View>
        </View>
    );
;

export default CharacterDetailScreen;

我检查了来自 API 的传入数据。是不是因为页面渲染的时候数据还没有从api来?

这里是来自 API 的传入数据示例:

const character = 
    "created": "2017-12-01T10:32:08.340Z", 
    "episode": ["https://rickandmortyapi.com/api/episode/5"], 
    "gender": "Male", 
    "id": 89, 
    "image": "https://rickandmortyapi.com/api/character/avatar/89.jpeg", 
    "location": "name": "Giant's Town", "url": "https://rickandmortyapi.com/api/location/14", 
    "name": "Dale", 
    "origin": "name": "Giant's Town", "url": "https://rickandmortyapi.com/api/location/14", 
    "species": "Mythological Creature", 
    "status": "Dead", 
    "type": "Giant", 
    "url": "https://rickandmortyapi.com/api/character/89"

【问题讨论】:

API 网址:rickandmortyapi.com/api 这是因为 setCharacter(characterDetail) 是异步过程,将数据设置为状态需要时间。您面临的错误是因为“字符”状态为空。 你应该在角色有一些数据时加载视图。添加逻辑以仅在数据可用字符时显示视图。 【参考方案1】:

解决此问题的简单方法是预先定义您的数据:

const [character, setCharacter] = useState(
    "created": "", 
    "episode": [], 
    "gender": "", 
    "id": 0, 
    "image": undefined, 
    "location": "name": "", "url": "", 
    "name": "", 
    "origin": "name": "", "url": "", 
    "species": "", 
    "status": "", 
    "type": "", 
    "url": ""
)

这样您就不必再猜测是否定义了字符的属性,并且您不必为可能使用的字符的每个参数添加空检查而头疼。

解决此问题的另一种方法是将默认字符设置为 null 并有条件地呈现用户界面

const CharacterDetailScreen = (props) => 

    const  styles, colors  = useThemedValues(getStyles);
    const loc = useLocalization();

    **// state for character detail**
    const [character, setCharacter] = useState(null])

    **// this id come from previous screen**
    const  characterId  = props.route.params

    useEffect(()=>
        Axios.get('character/'+characterId)
            .then(response =>
                characterDetail = response.data
                setCharacter(characterDetail)
                console.log(characterDetail.name) // if characterId=89, writes "dale" in console
            )
            .catch(error => 
                console.log(error)
            )
    ,[])
 
    return (
        <View style=styles.container>
            character ? (
                <View style=styles.imageContainer>
                    <Image source= uri: character.image  style=styles.image/>
                </View>
                <View style=styles.characterNameContainer>
                    <Text style=styles.characterName>character.name</Text>
                </View>
                <View style=styles.detailContainer>
                    <Text style=styles.detailText >loc.t(texts.status)character.status</Text>
                    <Text style=styles.detailText >loc.t(texts.species)character.species</Text>
                    <Text style=styles.detailText >loc.t(texts.gender)character.gender</Text>
                    <Text style=styles.detailText >loc.t(texts.type)character.type</Text>
                    <Text style=styles.detailText >loc.t(texts.origin)character.origin.name</Text>
                    <Text style=styles.detailText >loc.t(texts.location)character.location.name</Text>
                </View>
            ) : (
                <Loading/>
            )
        </View>
    );
;

export default CharacterDetailScreen;

【讨论】:

成功了!太感谢了!您对解决“source.uri 不应为空屏”警告有什么建议吗? 是的,使用 undefined 而不是空字符串,或者您可以使用默认图像预先填充它

以上是关于React Native - 渲染从 API 获取数据的屏幕时出现“未定义不是对象”错误的主要内容,如果未能解决你的问题,请参考以下文章

React native - 在渲染应用程序组件之前从异步存储中获取数据

FlatList 不渲染从服务器获取的父组件数据,在 React Native 的子组件中

在渲染组件之前 React Native fetch

React Native UseEffect API 调用

从 React Native 中的数组映射函数动态渲染内容

从 URL 获取 React-Native JSON