简体   繁体   中英

How do I update the state by updating an array within a particular object from an array of objects?

I have an array of objects addon_categories containing a property id and another array: addons . As the user toggles checkboxes, the state should update accordingly: which includes adding to or removing from 'addons' array under the selected category.

this.state = { addon_categories: [] };

// example of filled state
this.state = { addon_categories: [
     { id: 3, addons: [ 1 ] },
     { id: 2, addons: [ 1, 4, 11 ] },
     { id: 4, addons: [ 3, 4] }
 ] };

This is more of a problem of JavaScript more than React except that the data has to be finally updated as a component state. As a beginner of JavaScript, I'm unable to update the state object with arrays of objects containing some properties and arrays. In the code below, what is the correct logic to update the addons array (for both delete from and push to) just for the particular category?

Here's the logic:

  1. If category ID doesn't exist, simply add a new object with the category id and addons array with single addon id. [✓]

  2. If the category ID exists,
    -> check if the addon_id exists in this category.
    -> If addon_id exists in this category, remove the addon id from this addons array in this object [?]
    -> If addon_id doesn't exist, push this addon id to this addons array in this object [?]

Here is my code.

import React from 'react';
import { connect } from 'react-redux';
import store from '../../../../reducers/store';
import fetchFood from '../../../../actions/restaurant/food_get';

class AddonsModal extends React.Component
{
    constructor(props)
    {
        super(props);
        this.state = { addon_categories: [] };

        this.onAddonChange = this.onAddonChange.bind(this);
    }

    /*
     * Handle click, toggle addon change
     */
    onAddonChange(e)
    {
        const c = +e.target.name; // category_id from input
        const a = +e.target.id;   // addon_id from input

        // create new instance of this.state.addon_categories
        let addon_categories = this.state.addon_categories.slice();

        if (!this.addonCategoryExists(c))
        {
            // CATEGORY DOESNT EXIST, SO NEW CATEGORY AND ADDON ADDED!
            addon_categories.push({ id: c, addons: [a] });
            this.setState({ addon_categories }, () => console.log('NEW STATE', this.state.addon_categories));
        }
        else
        {
            // CATEGORY EXISTS
            if (this.addonExistsInCategory(c, a))
            {
                // ?? ADDON EXISTS IN THIS CATEGORY, SO NEED TO REMOVE IT
            }
            else
            {
                // ?? ADDON DOESNT EXIST IN CATEGORY SO NEED TO ADD IT TO JUST THIS CATEGORY
            }
        }

    }

    addonCategoryExists(c)
    {
        return !! this.state.addon_categories.filter(category => category.id === c).length;
    }

    addonExistsInCategory(c, a)
    {
        let verified = false;
        let categories = this.state.addon_categories.filter(category => category.id === c);
        categories.forEach(category =>
        {
            if (category.addons.includes(a)) { verified = true; }
        });
        return verified;
    }

    componentDidMount()
    {
        store.dispatch(fetchFood(this.props.Restaurant.id, this.props.food.id));
    }

    render()
    {
        let food = this.props.food;
        let foodData = this.props.foodDetails.food.data;
        let addon_categories = foodData ? foodData.data.addon_category : null;

        return (


                            <div className="row">

                                {addon_categories && addon_categories.map(category => { return (

                                    <div className="col-xs-12" key={category.id}>
                                        <div className="pop-up-dish-specials">
                                            <h2>{category.name}</h2>

                                            {category.addons && category.addons.map(addon => { return (

                                                <div  key={addon.id}>
                                                    {/* for simplicity, i've sent the category_id in name and addon_id in id property */}
                                                    <input type="checkbox" name={category.id} id={addon.id} onChange={this.onAddonChange}/>
                                                    <label htmlFor={addon.id}>{addon.name}</label>
                                                </div>

                                            )})}

                                        </div>
                                    </div>

                                )})}

                            </div>


        )
    }
}

function mapStateToProps(state)
{
    return { foodDetails: state.foodDetails }
}

export default connect(mapStateToProps)(AddonsModal);
    if (this.addonExistsInCategory(c, a)) {
      // ADDON EXISTS IN THIS CATEGORY, SO NEED TO REMOVE IT
      addon_categories.find(function(obj) {
        if (obj.id == c) {
          obj.addons.splice(obj.addons.indexOf(a), 1);
        }
      });
    } else {
      // ADDON DOESNT EXIST IN CATEGORY SO NEED TO ADD IT TO JUST THIS CATEGORY
      addon_categories.find(function(obj) {
        if (obj.id == c) {
          obj.addons.push(a);
        }
      });
    }
this.setState({ addon_categories }, () => console.log('NEW STATE', this.state.addon_categories));

I would just use simple .map and .filter if addon exists, therefore for removal:

const newCategories = this.state.addon_categories.map(category => {
    if (category.id === c) {
        const newAddons = category.addons.filter(addon => addon !== a);
        return { id: category.id, addons: newAddons };
    } else {
        return category;
    }        
});
this.setState({ addon_categories: newCategories });

for adding it would be like this:

const newCategories = this.state.addon_categories.map(category => {
    if (category.id === c) {
        const newAddons = category.addons.concat([a])
        return { id: category.id, addons: newAddons };
    } else {
        return category;
    }        
});
this.setState({ addon_categories: newCategories });

There is probably better solution to this problem though.

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