VSCode doesn’t mark this as invalid, despite the hooks being conditionally called:
function useHook() {
return 1;
}
function useHook2() {
const two = useMemo(() => 2, []);
return two;
}
const hookDictionary = {
useHook,
useHook2
}
export function HookUser(index) {
let func = hookDictionary[index];
func();
return null;
}
Is this intentional, and considered valid?
Is it being hidden by the use of hookDictionary
?
My assumption is that this is the case, since it’s functionally the same as the following which does throw an error:
export function HookUser(index: string) {
if (index === 'useHook') {
useHook();
} else if (index === 'useHook2') {
useHook2();
}
return null;
}
2
Answers
Consider this code :
Where HookUser is the same as yours. The moment I click on the button it will crash.
In this case your IDE seems to assume that the index will not change (since there is no condition inside of HookUser). Because in this case the condition is coming from other component, and the IDE doesn’t have the context to check for error (since HookUser isn’t considered as a hook)
You can export those hooks separately so there will never be an error like that.
Or you can also do
Intentional, no. Considered valid, also no.
Basically, yes. ESLint doesn’t do a deep-dive of your code to ensure it compiles and doesn’t create runtime errors. React hooks are really just regular old Javascript functions that have some special rules applied to them, namely the when and where they can be called. These functions are identified by their "use"-prefix.
The linter checking React hooks rules checks the first code:
Nothing fishy here, it checks out.
Then the second:
Ok, the
useMemo
hook is called. It’s unconditionally called from within another React hook, so it also checks out.Then the third and fourth code:
No hooks, i.e. no "use"-prefixed functions, called here, so these too also check out.
The linter doesn’t check references to see if the
func
function is really a React hook function in disguise. It wouldn’t be until the code is running and theindex
value changes and then a different hook was called from the previous render cycle, and an error is thrown indicating such. Even if you renamedfunc
touseFunc
, I still don’t think the Linter would be able to pick up on the switching abstracted behindhookDictionary[index]
.