Sorry for being pedantic, but the first example could be rewritten to extract the pattern into a higher level hook, eg useNotifications. One way to simplify components before reaching for store libraries. The reusable hook now contains all the state and effects and logic, and the component is more tidy.

    function Dashboard() {
      const { user } = useAuth();
      const {loading, error, notifications, undreadCount, markAsRead} = useNotifications(user);

      if (loading) return <Skeleton />;
      if (error) return <p>Failed to load: {error}</p>;

      return (
        <div>
          <h1>Dashboard ({unreadCount} unread)</h1>
          <StatsCards stats={stats} />
          <NotificationList items={notifications} onRead={markAsRead} />
        </div>
      );
    }

Working with multiple teams in a large project, hooks can be a nightmare to maintain.

I see 7x layers deep of hooks, with no test cases to support them. Some of the side effects are not properly tested, and mocks that abstract away the whole implementation means the test case only works for certain scenarios.

FWIW this scenario might be an outlier in large projects, considering how some developers prefer to "just wrap the hook in another hook, and not worry about its internals".

I was wondering if I was crazy for thinking "how is what he's suggesting different than just putting that 'class' into a hook function?" I'm glad to see someone already wrote it up, kudos.

@OP: PEBKAC, respectfully.

Far cleaner, how is testability though?

Very easy - mock the useNotifications and you can easily see all the behaviour by changing three properties.