return array of objects from props React JS

so I have the following component that is a dropdown list created using react-select.

import React from 'react'
import Select from 'react-select';

const options = [
  { value: 'chocolate', label: 'Chocolate' },
  { value: 'strawberry', label: 'Strawberry' },
  { value: 'vanilla', label: 'Vanilla' }
];


class MealsFilters extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      selectedOption: null,
    };
  }

  handleChange = (selectedOption) => {
    this.setState({ selectedOption });
    console.log(`Option selected:`, selectedOption);
  }

  render() {
    const { selectedOption } = this.state;
    return (
      <div className="container my-3">
        <div className="row">
          <div className="col-lg-4 col-md-6 col-sm-8">
            <Select
            isMulti
            isSearchable
            placeholder={"catégories"}
            value={selectedOption}
            onChange={this.handleChange}
            options={options}
            />
          </div>
        </div>
      </div>
    )
  }
}

export default MealsFilters;

the options variable is the default one from the docs. I actually need to replace its values by each meal category available. To do so, as you can see, I need to create an array of objects with a value and a label.

this component accesses meal categories through props called meals that are like so:

console.log(this.props.meals);

=> [{
     id: 0,
     name: spaghettis,
     category: italian,
     price: 5.99},
    {
     id: 1,
     name: hamburger,
     category: american,
     price: 7.99},
     {
      etc.
      }, {}]

How can I take advantage of this.props.meals to get my options array of objects ?

EDIT: multiple meals can have the same category, and I need each category to only appear once in the options.

4 answers

  • answered 2018-11-08 08:02 HMR

    You could do something like this:

    options={this.props.meals.map(
      ({id, name})=>({value:id,label:name})
    )}
    

    You could also use redux connect to create a container that will map the data to dropdown values for you

    You can merge the data by category in the following way:

    var items = [
      {
        id: 0,
        name: 'spaghettis',
        category: 'italian',
        price: 5.99,
      },
      {
        id: 1,
        name: 'hamburger',
        category: 'american',
        price: 7.99,
      },
      {
        id: 2,
        name: 'other hamburger',
        category: 'american',
        price: 7.99,
      },
    ];
    
    console.log(
      [
        ...items.reduce(
          (result, item) => (
            result.get(item.category)
              ? result.get(item.category).push(item.id)
              : result.set(item.category, [item.id]),
            result
          ),
          new Map(),
        ),
      ].map(([label, value]) => ({ label, value })),
    );

    In the component it'll look like this:

    options={[
      ...this.props.meals.reduce(
        (result, item) => (
          result.get(item.category)
            ? result.get(item.category).push(item.id)
            : result.set(item.category, [item.id]),
          result
        ),
        new Map(),
      ),
    ].map(([label, value]) => ({ label, value }))}
    

  • answered 2018-11-08 08:03 nrgwsth

    Map over your this.props.meals array, and create the needed options array,

    <Select
        isMulti
        isSearchable
        placeholder={"catégories"}
        value={selectedOption}
        onChange={this.handleChange}
        options={this.props.meal.map(item=>({value: item.id, label: item.name}))}
    />
    

  • answered 2018-11-08 08:12 kemicofa

    You only need the "name" property so when you map through meals, simply retrieve it. Then upper case the first letter.

    const meals = [{
        id: 0,
        name: "spaghettis",
        category: "italian",
        price: 5.99
      },
      {
        id: 1,
        name: "hamburger",
        category: "american",
        price: 7.99
      }
    ]
    
    const result = meals.map(({name}) => ({
      label: `${name[0].toUpperCase()}${name.slice(1)}`,
      value: name
    }))
    
    console.log(result);

  • answered 2018-11-08 08:13 Edward Sammut Alessi

    You can use getOptionLabel and getOptionValue props.

    <Select
        options={this.props.meals},
        getOptionLabel={m => m.name}
        getOptionValue={m => m.id} />
    

    https://react-select.com/props

    getOptionLabel generic = (option) => string

    Resolves option data to a string to be displayed as the label by components

    getOptionValue generic = (option) => string

    Resolves option data to a string to compare options and specify value attributes