-1

I have a react component that includes a dictionary of key/value pairs representing US state abbreviations for the key and their full name as the value like:

const states = {
  AL: "Alabama",
  AK: "Alaska",
  AZ: "Arizona",
  AR: "Arkansas",
  CA: "California"
}

I also have an API response that sends back a state as part of a nested address object as an abbreviation. So for California, the API returns CA

I'm trying to check the API response against my object and dynamically map only the US states that match what's in the dictionary to options in a select dropdown but I'm getting errors saying Expected an assignment or function call and instead saw an expression for my initial function.

I've included the dictionary look up function as well as my component below.

Dictionary lookup - causing the errors

const activeStates = props.locations.map(x => {abbr: x.address.state; name: states[x.address.state]});

React Component with select dropdown

<select>
  <option>
    {Object.entries(activeStates).map((name, abbreviation) => <option key={abbreviation} value={abbreviation}>{name}
  </option>
</select>
Josh
  • 1,165
  • 3
  • 24
  • 44
  • Very nearly a duplicate of https://stackoverflow.com/questions/45754957/why-doesnt-my-arrow-function-return-a-value (or maybe it even is one). – T.J. Crowder Feb 05 '20 at 15:48

2 Answers2

1

Because you have a { immediately after the =>, your arrow function uses a FunctionBody form and the { and ending } are the function's block, not an object literal. So you have code in the function that looks like:

abbr: x.address.state; name: states[x.address.state]

(I'm slightly surprised you're getting an error for that; it looks like valid code using labels to me, but... Or perhaps the error is from the code block cited below.)

If you want to use the concise form, put () around the object literal:

const activeStates = props.locations.map(x => ({abbr: x.address.state; name: states[x.address.state]}));
// −−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−^−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−^

You also have a couple of typos in your second code block, you don't have ) to end the map call's argument list, and you don't have } to end the JSX expression. Fixing those:

<select>
  <option>
    {Object.entries(activeStates).map((name, abbreviation) => <option key={abbreviation} value={abbreviation}>{name}
  </option>))}
</select>

But, Object.entries gives you an array of [key, value] arrays, so your parameter list for map should be using destructuring rather than two parameters (I'd also probably avoid making it quite so long, but that's a matter of style) and they'd be in the opposite order:

<select>
  <option>
    {Object.entries(activeStates).map(([abbreviation, name]) => (
        <option key={abbreviation} value={abbreviation}>{name}</option>
    ))}
</select>
T.J. Crowder
  • 1,031,962
  • 187
  • 1,923
  • 1,875
0

I ended up working it out by chaining a few mapping functions together with a filter like:

  let activeStates = props.locations.map(x => ({abbr: x.address.state, name: states[x.address.state]as string}));

  function getUnique(activeStates, comp) {

    const unique = activeStates
      .map(e => e[comp])
      // store the keys of the unique states
      .map((e, i, final) => final.indexOf(e) === i && i)
      // eliminate the duplicate keys and store unique states
      .filter(e => activeStates[e]).map(e => activeStates[e]);
     return unique;
  }

  let uniqueStates = getUnique(activeStates, 'abbr')

A bit of a roundabout but it ended up working and now all the options are mapping correctly. Thank you T.J. for the great suggestions!

Josh
  • 1,165
  • 3
  • 24
  • 44