React Native - "Undefined is not an object" 渲染从 API 获取数据的屏幕时出错

React Native - "Undefined is not an object" error when render a screen that take data from API

我是 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"
}

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

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

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

解决此问题的另一种方法是将字符默认为 null 并有条件地呈现 ui

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;