TransWikia.com

React Custom Hook run process when prop changes

Stack Overflow Asked on November 7, 2021

I’m new to React hooks and am attempting to make a custom hook that will concatenate arrays and remove the duplicate objects. I only want the hook to run that process if the prop changes to avoid un-needed processing.

I was attempting to cache concatenated results and use useMemo to only run if that changes but that does not work. Obviously, I am missing something with the way useMemo works.

I have tried various things mainly around slight tweaks, for example adding arrays to the useMemo dependencies as opposed to merged. Any help would be great. Thanks.

import * as React from "react";

let merged: any = [];
let result: any = [];

export const useRemoveDuplicateObjects = (arrays: any, value: string) => {
  merged = arrays.flat();

  const key = (item: any) => {
    return item[value];
  };

  const process = () => {
    result = [...new Map(merged.map((item: any) => [key(item), item])).values()];
  };

  React.useMemo(() => {
    if (merged.length) {
      process();
    }
  }, [merged]);

  return [result];
};

One Answer

Few things are not done properly here.

For starters, when you pass an array as a second parameter to useMemo, React will compare its values with strict equality, i.e. ===. The comparison will fail every time because you reassign your merged variable every time the hook is run.

If you want to compare the previous and new values contained by your array, there are 2 ways I can think of:

  1. pass directly merged as a second parameter instead of putting it in an array, this way React would compare the values within it directly. I don't know for sure if this would work, since maybe the values won't always be in the same order.
  2. you could store the "old" value of your array every time the hook runs (with a useState hook for instance) and compare this old value with the new one yourself, and then set a boolean accordingly. This way, this boolean can be passed as a second parameter within an array to your useMemo.

Also, as the documentation states, useMemo "returns an expensively computed value". So, to go along with how it works, you should get the "result" value this way :

   const result = React.useMemo(() => {
     if (merged.length) {
       return [...new Map(merged.map((item: any) => [key(item), item])).values()]
     }
     return []
   }, merged); // will or won't work, I'd say go with the comparison yourself as stated before

Finally, if you only want to return a single value from your hook, there's no need to wrap it in an array, you could just do it this way:

return result;

Answered by Littletime on November 7, 2021

Add your own answers!

Ask a Question

Get help from others!

© 2024 TransWikia.com. All rights reserved. Sites we Love: PCI Database, UKBizDB, Menu Kuliner, Sharing RPP