Skip to content

Commit 4893239

Browse files
committed
Add special case handling for render-hooks
1 parent 0cd9a6d commit 4893239

File tree

2 files changed

+34
-1
lines changed

2 files changed

+34
-1
lines changed

packages/eslint-plugin-react-hooks/__tests__/ESLintRulesOfHooks-test.js

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -337,6 +337,16 @@ const tests = {
337337
const [myState, setMyState] = useState(null);
338338
}
339339
`,
340+
`
341+
// Valid because render-hooks acts as a component boundary
342+
function App(props) {
343+
return props.isOpen
344+
? <Hooks>
345+
{() => <Modal close={useCallback(() => props.setIsOpen(false), [props.setIsOpen])} />}
346+
</Hooks>
347+
: null;
348+
}
349+
`,
340350
],
341351
invalid: [
342352
{
@@ -889,6 +899,21 @@ const tests = {
889899
`,
890900
errors: [classError('useState')],
891901
},
902+
{
903+
code: `
904+
// Invalid because rule of hooks still need to be adhered to within render-hooks
905+
function App(props) {
906+
return props.isOpen
907+
? <Hooks>
908+
{() => {
909+
return <Modal close={props.setIsOpen ? useCallback(() => props.setIsOpen(false), [props.setIsOpen]) : undefined} />;
910+
}}
911+
</Hooks>
912+
: null;
913+
}
914+
`,
915+
errors: [conditionalError('useCallback')]
916+
}
892917
],
893918
};
894919

packages/eslint-plugin-react-hooks/src/RulesOfHooks.js

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,14 @@ function isInsideComponentOrHook(node) {
104104
return false;
105105
}
106106

107+
function isDirectlyInsideRenderHooks(node) {
108+
return node.parent &&
109+
node.parent.type === 'JSXExpressionContainer' &&
110+
node.parent.parent &&
111+
node.parent.parent.type === 'JSXElement' &&
112+
node.parent.parent.openingElement.name.name === 'Hooks';
113+
}
114+
107115
export default {
108116
meta: {
109117
type: 'problem',
@@ -352,7 +360,7 @@ export default {
352360
const isDirectlyInsideComponentOrHook = codePathFunctionName
353361
? isComponentName(codePathFunctionName) ||
354362
isHook(codePathFunctionName)
355-
: isForwardRefCallback(codePathNode) || isMemoCallback(codePathNode);
363+
: isForwardRefCallback(codePathNode) || isMemoCallback(codePathNode) || isDirectlyInsideRenderHooks(codePathNode);
356364

357365
// Compute the earliest finalizer level using information from the
358366
// cache. We expect all reachable final segments to have a cache entry

0 commit comments

Comments
 (0)