Reputation: 3499
I am trying to understand the usage of useMemo. Since the object doesn't change, I thought I can improve performance by adding useMemo.
However as soon I add it here, I am being asked to add findFloorPosition
. Once I did that my linter asks me to add useCallback
to the findFloorPosition
function.
Can you give me some advice what's the right way to implement useMemo
here?
const location = useLocation();
const searchParams = parseQs(location.search);
const goto = searchParams?.goto;
const findFloorPosition = (elementId) => {
for (const floor of blueprint) {
for (const room of floor.rooms) {
const foundElement = room.elements.find(
(element) => element.id === elementId
);
if (foundElement) {
return floor.position;
}
}
}
};
const currentFloorPosition = useMemo(() => findFloorPosition(goto), [goto]);
Probably not relevant here, but here how the blueprint
object looks like:
const blueprint = [
{
id: "4mD59WO",
name: "AUDITORIUM",
position: 1,
rooms: [
{
id: "zR8Qgpj",
name: "Audimax",
subtitle: null,
details: null,
position: 0,
elements: [
{
id: "1jLv04W",
position: 0,
type: "daily",
element: "listing_large",
properties: {
meetingId: null,
capacity: 6
}
},
{
id: "1jLv12W",
position: 1,
type: "daily",
element: "listing_large",
properties: {
meetingId: null,
capacity: 6
}
}
]
}
]
},
{
id: "3mDd9WO",
name: "FOYER",
position: 0,
rooms: [
{
id: "4R8Qgpj",
name: "Speakers Table",
subtitle: null,
details: null,
position: 0,
elements: [
{
id: "2jLv04W",
position: 0,
type: "daily",
element: "listing_large",
properties: {
meetingId: null,
capacity: 6
}
},
{
id: "2jLv12W",
position: 1,
type: "daily",
element: "listing_large",
properties: {
meetingId: null,
capacity: 6
}
}
]
}
]
}
];
Upvotes: 0
Views: 415
Reputation: 281744
Since functional components rely heavily on closures, its extremely important that when you memoize functions, you are using the correct and updated values from the closures.
The reason eslint
warns you to add findFloorPosition
to dependency is to make sure that nothing within findFloorPosition refers to old values
The above code can be implemented like
const findFloorPosition = useCallback((elementId) => {
for (const floor of blueprint) {
for (const room of floor.rooms) {
const foundElement = room.elements.find(
(element) => element.id === elementId
);
if (foundElement) {
return floor.position;
}
}
}
}, [blueprint]);
const currentFloorPosition = useMemo(() => findFloorPosition(goto), [goto, findFloorPosition]);
Upvotes: 1
Reputation: 53894
Notice that you should memoize a value only if the dependency array values (the value of goto
) not frequently change.
The warning occurs because the linter (eslint
) only evaluates the semantics, it doesn't know that findFloorPosition
is just a helper function.
So basically you need to inline the helper function like:
const currentFloorPosition = useMemo(() => {
for (const floor of blueprint) {
for (const room of floor.rooms) {
const foundElement = room.elements.find(
(element) => element.id === goto
);
if (foundElement) {
return floor.position;
}
}
}
return null;
}, [goto]);
// Or
const currentFloorPosition = useMemo(() => {
const findFloorPosition = (elementId) => {
for (const floor of blueprint) {
for (const room of floor.rooms) {
const foundElement = room.elements.find(
(element) => element.id === elementId
);
if (foundElement) {
return floor.position;
}
}
}
};
return findFloorPosition(goto);
}, [goto]);
Upvotes: 0