Josh
Josh

Reputation: 1235

Using Array.find() to try and dynamically grab a specific object value and return it based on Object name, nothing returning from function

I have an array of object values each with it's own sub array of objects.

I'm attempting to use the Array.find() method to target each array node specifically and return a value from it's subarray based on name.

I have my function all written out but nothing is being returned and I keep getting a warning stating:

Expected to return a value at the end of the function(array-callback-return)

And I'm not entirely sure what I'm missing.

The function and data structure for reference as well as a CodeSandbox:

const subjectTypes = [
  {
    name: "pokemon",
    details: [
      {
        type: "subtitle",
        value: "This is the subtitle for pokemon"
      }
    ]
  },
  {
    name: "marvel",
    details: [
      {
        type: "subtitle",
        value: "This is the subtitle for marvel"
      }
    ]
  }
];

const setCustomValue = (location) => {
  let value;

  switch (location) {
    case "/pokemon":
      return (value = subjectTypes.find(function (subject, idx) {
        if (subject.name === "pokemon") return subject.details.value;
      }));
    case "/marvel":
      return (value = subjectTypes.find(function (subject, idx) {
        if (subject.name === "marvel") return subject.details.value;
      }));
    default:
      return null;
  }
};

const customValue = setCustomValue("/pokemon");

export default function App() {
  return (
    <div className="App">
      <h1>Hello CodeSandbox</h1>
      <h2>Dynamically Populated Content Below:</h2>
      <p>{customValue}</p>
    </div>
  );
}

Also I'm aware that this may appear like over engineering and that I could easily just use a .map() or similar to print out values, but I'm using this as a simplified version of a larger problem I'm trying to solve that requires something like the .find() method to return a specific result.

Upvotes: 2

Views: 948

Answers (3)

Belhadjer Samir
Belhadjer Samir

Reputation: 1659

The find() method returns the value of the first element in the provided array that satisfies the provided testing function. If no values satisfy the testing function, undefined is returned.

it will return all the element that satisfies the provided testing function

try like this :

return subjectTypes.find(function (subject,idx) {
        return subject.name === "pokemon"
        
}).details[0].value

details it is not an object it is an array so you have to select the oject inside the array then get the value of it

or you can simply use arrow function like this

reuturn subjectTypes.find( (subject,idx)=> 
      subject.name === "pokemon"  
).details[0].value

Upvotes: 1

VLAZ
VLAZ

Reputation: 28970

  1. Array#find() expects a true or false from the callback. Or at the very least a truthy or falsy value.

  2. The ESLint rule array-callback-return reports a related problem. The callback only returns something from the if, not when the condition is not met. This is normally valid - no return makes the function implicitly return undefined. Since this value is falsy, find will ignore this item and continue with the next one. However, the ESLint rule is there to make these returns explicit and prevent mistakes, in case it is actually a bug that a branch of code does not return anything.

  3. In the callback the return value is subject.details.value but the actual path is subject.details[0].value because subject.detailsis an array. Therefore the only return you have, produces undefined.

  4. It's not possible to both locate a value with .find() and modify what is returned at the same time. You need to return the value first and then get a sub-section of it.

  5. No need to declare and assign value when it is never used.

To address these, here is the code a bit cleaned up:

const setCustomValue = (location) => {
  let value;
  switch (location) {
    case "/pokemon":
      value = subjectTypes.find(function (subject, idx) {
        return subject.name === "pokemon";
      });
      return value.details[0].value;
    case "/marvel":
      value = subjectTypes.find(function (subject, idx) {
        return subject.name === "pokemon";
      });
      return value.details[0].value;
    default:
      return null;
  }
};

To avoid some of the repetition, you can extract the .find() and return logic outside the switch:

const setCustomValue = (location) => {
  let name;
  switch (location) {
    case "/pokemon":
      name = "pokemon";
      break;
    case "/marvel":
      name = "marvel";
      break;
    default:
      return null;
  }

  const value = subjectTypes.find((subject) => subject.name === name);
  return value.details[0].value;
};

The whole switch can be eliminated by using a simple lookup instead:

const paths = {
  "/pokemon": "pokemon",
  "/marvel": "marvel",
}
const setCustomValue = (location) => {
  let name = paths[location];

  if (!name) 
    return null;

  const value = subjectTypes.find((subject) => subject.name === name);
  return value.details[0].value;
};

And even more minimal using optional chaining and the nullish coalescing operator

const paths = {
  "/pokemon": "pokemon",
  "/marvel": "marvel",
}
const setCustomValue = (location) => 
  subjectTypes.find((subject) => subject.name === paths[location])?.details[0].value ?? null;

Upvotes: 2

Sinan Yaman
Sinan Yaman

Reputation: 5937

Find returns you the element, based on a boolean query. So you have to find through name, and then get that element's value

Try:

return (value = subjectTypes.find( function (subject, idx) {
  return subject.name === "pokemon";
}).details.value);

A cleaner way of writing this, in my totally personal opinion:

value = subjectTypes.find( 
  subject => subject.name === "pokemon"
).details.value

Upvotes: 1

Related Questions