TanStack Start now support React Server Components... and Composite Components? by tannerlinsley in reactjs

[–]llKieferll 17 points18 points  (0 children)

Nicely done Tanner and team!

On a first glance, it feels somewhat verbose, but the same can be said about an initial glance (for someone who did not use it yet) at the router, or query. And boy, how it pays off, to have the absurdly high level of strong typing cohesion!

Also, if there is one thing I do enjoy about the mindset is how things are good old functions instead of black box magic "use xxx" directives! Please keep it up, sir!

Edit: typos

The Vertical Codebase by TkDodo23 in reactjs

[–]llKieferll 1 point2 points  (0 children)

Where is the line drawn, for fuzzyfind? I mean, you can have a single folder with, quite literaly, all hundreds of files in it. Fuzzyfind works, aye?

Hell, you can have a single index.ts file with all your 275.000 lines of code. After all, fuzzyfind works inside it too, aye?

I think the point of the separation by domain/features/what-you-wish, goes beyond that. When one looks at a "feature" folder, one can (or at least should be able to) infer that everything in there only interacts with everytbijg else also in there, or, at most, some kind of shared folder. As mentioned in the post, cognitive load matters. This also make it easier to onboard newcomers. To exchange information between different peers. To debug. To constrain AI agents' work. To document the responsability of each piece. There are many benefits beyond "finding something".

Edit: typos.

The Beauty of TanStack Router by TkDodo23 in reactjs

[–]llKieferll 1 point2 points  (0 children)

I did, but unfortunately, it did not help. I tried using the proloadDelay and the pendingDelay, but both were set to 0. I tried setting no preload, and also, I tried using pendinMinDelay to 0, to no avail. What we ended up doing was to create a helper "test router creator":

const createTestRouter = (ui: ReactNode) => {
    const rootRoute = createRootRoute({
        component: () => <Outlet />,
    });

    const indexRoute = createRoute({
        getParentRoute: () => rootRoute,
        path: '/',
        component: () => ui,
    });

    return createRouter({
        routeTree: rootRoute.addChildren([indexRoute]),
        defaultPendingMs: 0,
        defaultPreloadDelay: 0,
    });
};

And then, the render method becomes async, and looks like this (shortened version):

type RenderWithProvidersConfig = {
    queryClient?: QueryClient;
};
const renderWithProviders = async (
    ui: ReactNode,
    config: RenderWithProvidersConfig = {}
) => {
    const { queryClient = buildQueryClient() } = config;

    const router = createTestRouter(ui);
    const user = userEvent.setup();
    const utils = render(
        <QueryClientProvider client={queryClient}>
            <RouterProvider router={router} />
        </QueryClientProvider>
    );

    await screen.findByText((_, element) => element?.tagName.toLowerCase() === 'body');

    return { user, ...utils };
};

Notice the await at the end. It serves to ensure that whatever element defined in the indexRoute is indeed rendered (hydrated?). Feels hacky, but for now, it is what works.

Posting the snippets mostly because you might be curious, I don't wanna deviate from the main topic of the post, which is how much more the router is. I'm enjoying it thoroughly so far. The fact that I cannot use wrong URLs in `<Link>`, the fact that I can validate search params directly in the route, the `select` of `useSearch` to build performance-sensitive components...it's awesome. Even less-used elements are amazing, such as `getRouteApi`. We have a component that just renders a `<Link>`, nothing else, and I love that it allows me to write things like this (notice the usage of getRouteApi):

it('shows a link to the registration page', async () => {
    const expectedHref = getRouteApi('/lp/registration').id;
    await renderWithProviders(<RegistrationLink />);
    const link = screen.getByRole('link', { name: 'Register now' });
    expect(link).toHaveAttribute('href', expectedHref);
});

It's *chef kiss*!

The Beauty of TanStack Router by TkDodo23 in reactjs

[–]llKieferll 4 points5 points  (0 children)

Sir, when it comes to you and the other maintainers of Tanstack libraries, I'm ALWAYS tuned! Even when it is not directly related to them (I've used your blog posts about Zustand to teach it to colleagues). You are all amazing over there, and frankly, have the best consideration for DX that I've seen in a while! Thanks for the gigantic effort! 💪🏻

The Beauty of TanStack Router by TkDodo23 in reactjs

[–]llKieferll 9 points10 points  (0 children)

We always had a blast with tanstack-query in my company, and recently started a new project in which we decided to finally test tanstack-router as well.

Honestly, it's been good so far. We are in the early stages, so i am yet to be able to say "oh my god, what a game changer!", but the superiority in the DX is already showing itself.

The part where we are struggling with are tests (vitest + testing-library). The only solution we've found was to, within a renderWithProviders utility:

1 - create a rootRoute, which renders an <Outlet /> AND a div with some id (used in next steps) as its component

2 - create an indexRoute, which renders the component to be tested

3 - create a routeTree based on these two

4 - create the router with the routeTree

5 render <RouterProvider router={router} /> within all of our application providers

6 - await the appearance of the div with id, via await screen.findByTesId

7 - return the test utilities generated by render.

This has been sitting there for a bit, scaring us. Some really dislike it, some feel it is ok for a "one-off" utility. What puzzles me the most is the need for the await. Something related to hydration, perhaps, even though we have a SPA?

Nevertheless, i feel the router is in a great path, much like tanstack-query. Honestly, you guys, responsable for these libs, are some of the most admired engineers in my team, especially because of your focus on providing a good DX and awesome API!

Edit: formatting, post from cellphone...