Skip to content

Commit 0c0d89f

Browse files
authored
[react-transform] Prepend useSignals call if function isn't clearly a component (#458)
It's possible to use the `@trackSignals` comment manually opt-in to the react signals transform on a function that isn't obviously a Component or hook. Before, we would always wrap those functions in a `try/finally` clause. However, this could break signal tracking if the function was actually used as a hook. For example: ```js /** @trackSignals */ function badHookName() { try { // When this hook runs it will close any open effect. Specifically, // the effect in Component. This means, upon exiting this hook, // all effects will be closed and any signals accesed in "... other stuff ..." // in Component will be missed. const e = useSignals(); ... } finally { e.f() // Finish this hook's effect } } function Component() { try { const e = useSignals(); badHookName(); // .. other stuff ... } finally { e.f(); // Finish this hook's effect. } | ``` We fix the bug described in the comment above by just prepending `useSignals()`. This method of tracking signals in React relies on a microtick to close the effect meaning any signals accessed in "... other stuff ..." will be captured by this effect. More improvements to this scenario will come in a follow up PR. This PR also adds more tests for transforming hooks in general.
1 parent 03bb907 commit 0c0d89f

File tree

4 files changed

+469
-272
lines changed

4 files changed

+469
-272
lines changed

.changeset/little-donuts-notice.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@preact/signals-react-transform": minor
3+
---
4+
5+
Only prepend useSignals call if we can't determine whether a function is a component or hook

packages/react-transform/src/index.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -348,8 +348,12 @@ function transformFunction(
348348
// component. The try/finally in the component's body will stop tracking
349349
// signals for us instead.
350350
newFunction = prependUseSignals(t, path, state);
351-
} else {
351+
} else if (isComponentName(functionName)) {
352352
newFunction = wrapInTryFinally(t, path, state);
353+
} else {
354+
// Since we can't determine if this function is a component/hook or not,
355+
// we'll just prepend the useSignals call so it will work as either
356+
newFunction = prependUseSignals(t, path, state);
353357
}
354358

355359
// Using replaceWith keeps the existing leading comments already so

0 commit comments

Comments
 (0)