Hacker News new | ask | show | jobs
by mattkrick 2470 days ago
Hooks are absolutely fantastic. However, there are still a few pain points:

- useState with an array is bad news if more than 1 component is consuming or setting the state.The clunky alternative is to keep it in a ref & call a forceUpdate whenever you would normally call your setter

- useCallback doesn't scratch the itch for things like document event listeners since everything inside the callback will be stale. The clunky alternative is a custom useEventCallback that keeps your callback function in a ref. (and that might not work in the upcoming sync mode)

- linter rules can be too strict & the --fix flag can actually cause a break in your app by adding things to the dependency list. Sometimes a useEffect depends on the current value of a ref, but linter says that's a no-no. 2 useCallbacks can be co-dependent, but there's no way to write that co-dependence in the dependency list. Sometimes I want to return null before a hook. The clunky alternative for all these is a bunch of eslint-ignore comments.

1 comments

> useState with an array with more than 1 component setting the state...

It sounds like you might be setting state by modifying the array and then calling the setter. This won't work:

    array.push(thing)
    setArray(array)
Instead, you have to update the array immutably, like setArray([...array, thing]).

> useCallback for event listeners

useEffect is usually the right place to set up event listeners (and has a built-in way of cleaning them up, by returning a cleanup function).

> Sometimes I want to return null before a hook.

Hooks pretty much have to be at the very top of the component, and eslint-ignore'ing those errors will probably cause weird issues later. Better to think about another way to solve the problem that doesn't involve returning early.

An issue I ran into recently: I had a modal Edit dialog with some form state that was initialized with the current values of the thing I wanted to edit. If that modal was always mounted and merely shown/hidden (<Modal isOpen={itemToEdit}/>), the state would be initialized once and wouldn't update when I changed the item-to-be-edited. The fix was to unmount the dialog, and only mount it when there was an item to edit, {itemToEdit && <Modal isOpen={true}/>}