1

I'm using React Native memo to decide whether my component should re-render or not. My props need more than a shallow compare so I figured I can use Lodash isEqual. However, for some reason it returns false for identical objects. The issue is a prop userChildren which is an array of objects. To get it to work I need to remap the whole array which I don't understand why that would be needed.

const areEqual = (
  { userChildren: prevChildren, ...prevProps },
  { userChildren: nextChildren, ...nextProps }
) => {
  console.log(
    _.isEqual(
      prevChildren.map((p) => ({ ...p })),
      nextChildren.map((p) => ({ ...p }))
    )
  ); // Returns true
  console.log(_.isEqual(prevChildren, nextChildren)); // Returns false
  console.log(prevChildren);
  console.log(nextChildren);
  return (
    _.isEqual(prevProps, nextProps) &&
    _.isEqual(
      prevChildren.map((p) => ({ ...p })),
      nextChildren.map((p) => ({ ...p }))
    )
  );
};

export default memo(RootNavigator, areEqual);

The log output can be seen below:

 LOG  true
 LOG  false
 LOG  [{"birthDate": "2022-09-14", "firstName": null, "gender": null, "id": "189", "showGender": null, "userId": "XXX"}]
 LOG  [{"birthDate": "2022-09-14", "firstName": null, "gender": null, "id": "189", "showGender": null, "userId": "XXX"}]

EDIT

There seems to be something with nextProps that breaks the isEqual:

console.log(
  'nextChildren',
  _.isEqual(
    [
      {
        birthDate: '2022-09-14',
        firstName: null,
        gender: null,
        id: '189',
        showGender: null,
        userId: 'XXX',
      },
    ],
    nextChildren
  )
);
console.log(
  'prevChildren',
  _.isEqual(prevChildren, [
    {
      birthDate: '2022-09-14',
      firstName: null,
      gender: null,
      id: '189',
      showGender: null,
      userId: 'XXX',
    },
  ])
);

Gives the log output:

LOG  nextChildren false
LOG  prevChildren true
9
  • AFAIK lodash's .isEqual() compares objects by reference.
    – KarelG
    Commented Sep 15, 2022 at 14:13
  • 2
    Does it? I thought the whole point was that it does not: geeksforgeeks.org/lodash-_-isequal-method Commented Sep 15, 2022 at 14:15
  • 2
    @KarelG you are mistaken. _.isEqual({"foo":"bar"}, {"foo":"bar"}) is true
    – Wyck
    Commented Sep 15, 2022 at 14:16
  • 2
    @DanielTovesson Perhaps you could make this into a runnable snippet that fully demonstrates the problem? See How do I create a React Stack Snippet with JSX support?
    – Wyck
    Commented Sep 15, 2022 at 14:21
  • I tested isEqual with your log output and it is returning true. So the issues is in your props object. Since it is react, the library might include its own properties, which is not openly available for processing. I am not sure on the exact term on that. I would recommend to convert to string and base64 and compare which would provide proper comparison Commented Sep 15, 2022 at 14:25

1 Answer 1

0

I had isEqual return false as well, but in my case, I overlooked that one object contained two strings while the other contained a string and a number.

{"label":"Xã Thượng Lâm", "value":"2269"} 
{"label":"Xã Thượng Lâm", "value":2269}

So if you have the same error message, don't forget to check your types.

Not the answer you're looking for? Browse other questions tagged or ask your own question.