Fork me on GitHub
#helix
<
2021-10-15
>
JonR21:10:23

Just did a long trip down the rabbit hole to really try and understand this and thought I would share thoughts. Main take aways were: • Having used reagent for the last 6+ years led to a major misconception that React defaulted to compare props, now I understand that Reagent does this by default not react • Even if you are passing immutable data structures as props you are still creating a new props map • Deep equals (`=`) will work in this case because values can be equal but identical? will fail • The function @lilactown shared works because it checks shallow equality via map entry count and identical? @lilactown you called all this out but I still needed to bang my head against the wall a bit and work with a team member to make an exhaustive test. One more question, since we are using our own defnc with a factory component flag we need this custom memo fn right? Meaning, if we were using raw dom tags with prop maps those would work as expected with the default memo comparator?

1
lilactown23:10:11

@jon693 I had to bang my head on it a lot until it sunk in 🙂 glad I was able to help a bit. > since we are using our own `defnc` with a factory component flag we need this custom memo fn right? that's right. if you were using defnc without the :define-factory feature flag turned on, which means you would create elements out of your components using ($ my-component ,,,) instead of (my-component ,,,), then you would not need the custom factory-props-kvs-identical? compare I wrote above

JonR23:10:21

If I remember right we needed the factory bit so we could call our components without $.

JonR23:10:45

So maybe that added extra complexity

JonR23:10:55

Err, it did!

lilactown23:10:22

yup. the reason why memo is misbehaving here is that ($ my-component {:foo "bar" :baz 123}) turns the map you pass in to a JS object, {"foo": "bar", "baz": 123} , that React can read and compare with memo. the factory function doesn't turn the map you pass in, into a JS object. instead, it passes it as a single prop, {"helix/props": {:foo "bar", :baz 123}} React's memo by default compares each key in the props object using identical? . so it will compare the map in the "helix/props" property between each render, get a different result, and fail the memo check. using $ the memo check would succeed and it wouldn't bother calling the component.

lilactown23:10:50

the factory-props-kvs-identical? function essentially replicates this logic that React does with the props object, with the nested "helix/props" map

lilactown23:10:33

I think this should be the default behavior of helix.core/memo tbh I just hadn't run into this edge case before. I don't use :define-factory

JonR23:10:24

Doh, which is why helix props are always referential different

JonR23:10:04

In our defnc case

lilactown23:10:24

yep exactly! 😄