简体   繁体   中英

React Javascript Handle Possible Null Data

I am using React to build a simple app that gets data back from some API. I am not sure what is the best way to handle the fields when some of them doesnt come back. For example, Let's say the JSON data comes back looking like the following

comicDetail : {
    name : iron man, 
    age: {
        comicAge: 35,   
    },
    favouriteFood: {
        fruit: {
            apple
        }
    }
    hobby: {
        favourite: {
            build machines        
        }
    }
    series: [iron man 1, iron man 2]
    relationship: {
        jane: iron man 1, 
        Mary: iron man 2
    }, 
    collection : {
            image : www.image1.com 
        }            
    }
}

My React code that renders the data

renderComicDetail() {
    var cd = this.props.comicDetail;        
    if (!cd) {
        return (
            <div>No Data</div>
        )
    }
    const imageUrl = cd.collection.image
    return (
        <div>
            <div>age: {cd.age.comicAge}</div>                
            <div>favourite fruit: {cd.favouriteFood.fruit}</div>                
            <div>favourite hobby: {cd.hobby.favourite}</div>                
        </div>
    )
}

This code will break if either of the of cd.favouriteFood, cd.age, cd.hobby is undefined as I will be reading from undefined. (This will happen as not all fields will come back) What is the cleanest way to allow me to read the data and take care of the undefined case so I dont read .fruit from undefined.

A way I can think of is to have check cases for each part of the json data for every item. But it seems messy and will not be scalable as I might have data that looks like

You can specify a condition to render a component in JSX, your code would look something like this (assuming that if hobby or food are defined then it would have renderable properties):

var cd = this.props.comicDetail;        
    if (!cd) {
        return (
            <div>No Data</div>
        )
    }
    const imageUrl = cd.collection.image;


    return (
        <div>
            <div>age: {cd.age.comicAge}</div>                
            {cd.favouriteFood && <div>favourite fruit: {cd.favouriteFood.fruit}</div>}
            {cd.hobby && <div>favourite hobby: {cd.hobby.favourite}</div>}
        </div>
    )

I also advice you to either create separate componet for both hobby and food, so it can make your code more readable and reusable. But it definitely depends on your specific usage.

if you only don't want to display content which is undefined, you can do like this:

return (
        <div>
            {cd.age && cd.age.comicAge ? <div>age:{cd.age.comicAge}</div> : <div>No data</div> 
            } 
            {cd.favouriteFood && cd.favouriteFood.fruit ? <div>favourite fruit: {cd.favouriteFood.fruit}</div> : <div>No data</div> 
            } 
            {cd.hobby && cd.hobby.favourite ? <div>favourite hobby: {cd.hobby.favourite}</div> : <div>No data</div> 
            }                                            
        </div>
    )

or if you don't want like this, create a separate function that checks valid fields

if (!isValid(cd)) {
        return (
            <div>No Data</div>
        )
 }

isValid(obj){
  // check if all objects available are valid or not and return true or false as needed.
}

如何使用三元运算符?

cd.age !== undefined ? cd.age.comicAge : ' '

You can use any JSON schema validator for this purpose and there are lots of them. for eg jsonschema

In your case you can create schema something like this ( for first two properties)

var schema = {
"id": "/ComicDetail",
"type": "object",
"properties": {
    "name": {
        "type": "string"
    },

    "age": {
        "type": "object",
        "properties": {
            "comicAge": {
                "type": "integer"
            }
        }
    }
},
"required": ["name", "age"]
};

You can also embed two or more schema together and form a new schema.

One way to access deep object property using lodash. You can import lodash in your component.

_.get(cd, 'favouriteFood.fruit') || ''

https://lodash.com/docs/4.16.6#get

To make the code cleaner, You can also declare a function that takes your object(ie cd in your case) and path(ie favouriteFood.fruit in your case) and return the value from function.

I really like this method of un-nesting objects:

// Below will not error out, but give undefined when you use the non-existant variables
const { cd } = (this.props || {}).comicDetail || {}
const { imageUrl } = ((cd || {}).collection || {}).image || {}

// Or
const { age, favouriteFood, hobby } = cd
const { comicAge } = age // forgot if you need to add || {} here
const { fruit } = favouriteFood
const { favourite } = hobby

You always want to validate your variables and you never want your variables to break during validation.

So now, you can safely use these 'potentially' undefined variables and validate that they contain values before you use them.

favorite || 'defaultValue'
if (!favorite) return null 

You can try your return statement such like that:

return (
        <div>
            { cd.age.comicAge && <div>age: {cd.age.comicAge }</div>}
            { cd.favouriteFood.fruit &&  <div>favourite fruit: {cd.favouriteFood.fruit}</div> }          

            {cd.hobby.favourite &&  <div>favourite hobby: {cd.hobby.favourite}</div>                
        </div>
    )

If your any prop is null or undefined, the right side of the condition is skipped.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM