What's the difference between `useCallback` with an empty array as inputs and `useCallback` without a second parameter?

For both useMemo and useCallback (which is essentially just a special case of useMemo), if the second argument is an empty array, the value will be memoized once and always returned.

If the second argument is omitted, the value will never be memoized, and the useCallback and the useMemo doesn't do anything.

Perhaps there's some edge case where you might conditionally memoize:

useMemo(someValue, shouldMemoize ? [] : null)

But in the vast majority of cases, the second argument to both useMemo and useCallback should be considered mandatory. And in fact, the Typescript definitions treat them this way.

// Require a second argument, and it must be an array
function useCallback<T extends (...args: any[]) => any>(callback: T, deps: DependencyList): T;

// Second argument can be undefined, but must be explicitly passed as undefined, not omitted.
function useMemo<T>(factory: () => T, deps: DependencyList | undefined): T;

There's an open pull request that's enhancing the exhaustive-deps hooks eslint rule so that it will raise a lint error if the second argument is omitted, so pretty soon this will likely be a linter error.