Reputation: 1235
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
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
Reputation: 28970
Array#find()
expects a true
or false
from the callback. Or at the very least a truthy or falsy value.
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.
In the callback the return value is subject.details.value
but the actual path is subject.details[0].value
because subject.details
is an array. Therefore the only return you have, produces undefined
.
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.
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
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