question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Issue with curried HOC

See original GitHub issue

Hello!

Last December I opened an issue (#404) regarding a problem with HMR when Prefresh encounters out of date references, caused by circular dependencies.

I started reworking my code to stop having to rely on these circular dependencies in the first place, but encountered a second problem in doing so: it seems like Prefresh does not support currying for HOC.

Reproduction and investigation details

If we take the following code:

// Dummy curried HOC for reproduction purpose that does nothing interesting...
const withDisplayName = (displayName) => (Component) => {
  Component.displayName = displayName
  return () => <Component receivedDisplayName={displayName} />
}

const MyComponent = withDisplayName('MyCurriedHoc')((props) => {
  return <div>{props.receivedDisplayName}</div>
})

If we look at the output of @prefresh/babel-plugin, we see the following

const withDisplayName = (displayName) => (Component) => {
  Component.displayName = displayName;
  return () => /* @__PURE__ */ h(Component, {
    receivedDisplayName: displayName
  });
};
const MyComponent = withDisplayName("MyCurriedHoc")((props) => {
  return /* @__PURE__ */ h("div", null, props.receivedDisplayName);
});

As we can see, the plugin did not save the reference to the component and does not register it for refresh. Interestingly enough in this precise situation, the first change made to the component… Correctly gets updated through HMR (using @web/dev-server). I don’t really know why this is happening since the if (import.meta.hot) { bit is nowhere to be seen in the transformed code.

The second change however, triggers a full reload of the page (which is normal considering HMR handling has not been injected).

Next I tried storing the first currying stage in a temporary variable, as follows:

const withDisplayName = (displayName) => (Component) => {
  Component.displayName = displayName
  return () => <Component receivedDisplayName={displayName} />
}

const withCurriedName = withDisplayName('MyCurriedHoc')

const MyComponent = withCurriedName((props) => {
  return <div>{props.receivedDisplayName}!!!</div>
})

With this change, the transformed output becomes:

const withDisplayName = displayName => Component => {
  Component.displayName = displayName;
  return () => /* @__PURE__ */h(Component, {
    receivedDisplayName: displayName
  });
};

const withCurriedName = withDisplayName("MyCurriedHoc");
const MyComponent = withCurriedName(_c = props => {
  return /* @__PURE__ */h("div", null, props.receivedDisplayName);
});
_c2 = MyComponent;
export const StubbablePlayground = MyComponent;

var _c, _c2;

$RefreshReg$(_c, "MyComponent$withCurriedName");
$RefreshReg$(_c2, "MyComponent");

          if (import.meta.hot) {
            self.$RefreshSig$ = prevRefreshSig;
            self.$RefreshReg$ = prevRefreshReg;
            import.meta.hot.accept(() => {
              try {
                flushUpdates();
              } catch(e) {
                import.meta.hot.invalidate();
              }
            });
          }

Now we can clearly see that HMR handling has been injected as expected, and with this everything works fine.

Is this a known limitation? It would really help not having to rely on a temporary variable to store the curried HOC before calling it.

I’ve looked into the code of @prefresh/babel-plugin but I’m not knowledgeable enough in Babel to know where to add checks for this myself.

Issue Analytics

  • State:closed
  • Created 2 years ago
  • Comments:10 (10 by maintainers)

github_iconTop GitHub Comments

1reaction
JoviDeCroockcommented, Jan 28, 2022

Not really as there are multiple unnamed funcs in there 😅 I’ll try to take a closer look tonight

0reactions
jvdsandecommented, Jan 28, 2022

There you go 😃 Thanks for you help and let see if we can make this work 😃

Read more comments on GitHub >

github_iconTop Results From Across the Web

React hooks inside a curry function (creating a HOC) returning ...
React hooks inside a curry function (creating a HOC) returning an error from linter 'React Hook "useContext" cannot be called inside a callback'....
Read more >
Spice Up React with Composition and Currying
Avoid property collisions with function currying and composition. React Higher-Order Components (HOC) are not dead; in fact, they are a handy tool when...
Read more >
Higher order components and currying in React
Higher order components, or HOC, are simply functions that take a component as an argument. Here's an example of a higher order component:....
Read more >
Currying
In this section we will remedy this problem by a pragmatic, ad hoc currying made via use of a simple higher-order function we...
Read more >
Improve type inference for generic curried functions #15016
This issue is about improving contextual typing of function expressions by generic function signatures. The issue you linked to is about ...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found